def test_site_families(): syst = builder.Builder() fam = builder.SimpleSiteFamily() ofam = builder.SimpleSiteFamily() yafam = builder.SimpleSiteFamily('another_name') syst[fam(0)] = 7 assert syst[fam(0)] == 7 assert len(set([fam, ofam, fam('a'), ofam('a'), yafam])) == 3 syst[fam(1)] = 123 assert syst[fam(1)] == 123 assert syst[ofam(1)] == 123 raises(KeyError, syst.__getitem__, yafam(1)) # test site families compare equal/not-equal assert fam == ofam assert fam != yafam assert fam != None assert fam != 'a' # test site families sorting fam1 = builder.SimpleSiteFamily(norbs=1) fam2 = builder.SimpleSiteFamily(norbs=2) assert fam1 < fam2 # string '1' is lexicographically less than '2'
def test_attach_lead(): fam = builder.SimpleSiteFamily(norbs=1) fam_noncommensurate = builder.SimpleSiteFamily(name='other') syst = builder.Builder() syst[fam(1)] = 0 lead = builder.Builder(VerySimpleSymmetry(-2)) raises(ValueError, syst.attach_lead, lead) lead[fam(0)] = 1 raises(ValueError, syst.attach_lead, lead) lead[fam(1)] = 1 syst.attach_lead(lead) raises(ValueError, syst.attach_lead, lead, fam(5)) syst = builder.Builder() # The tag of the site that is added in the following line is an empty tuple. # This simulates a site family that is not commensurate with the symmetry of # the lead. Such sites may be present in the system, as long as there are # other sites that will interrupt the lead. syst[fam_noncommensurate()] = 2 syst[fam(1)] = 0 syst[fam(0)] = 1 lead[fam(0), fam(1)] = lead[fam(0), fam(2)] = 1 syst.attach_lead(lead) assert len(list(syst.sites())) == 4 assert set(syst.leads[0].interface) == set([fam(-1), fam(0)]) syst[fam(-10)] = syst[fam(-11)] = 0 syst.attach_lead(lead) assert set(syst.leads[1].interface) == set([fam(-10), fam(-11)]) assert len(list(syst.sites())) == 6 syst.attach_lead(lead, fam(-5)) assert set(syst.leads[0].interface) == set([fam(-1), fam(0)]) # add some further-than-nearest-neighbor hoppings hop_range = 3 lead = builder.Builder( VerySimpleSymmetry(1), conservation_law=np.eye(1), time_reversal=np.eye(1), particle_hole=np.eye(1), chiral=np.eye(1)) lead[fam(0)] = 1 for i in range(1, hop_range + 1): lead[fam(0), fam(i)] = 1 syst.attach_lead(lead) expanded_lead = syst.leads[-1].builder assert expanded_lead.symmetry.period == hop_range assert len(list(expanded_lead.sites())) == hop_range assert expanded_lead.conservation_law is lead.conservation_law assert expanded_lead.time_reversal is lead.time_reversal assert expanded_lead.particle_hole is lead.particle_hole assert expanded_lead.chiral is lead.chiral # check that we can actually finalize the system syst.finalized()
def test_discrete_symmetries(): lat = builder.SimpleSiteFamily(name='ccc', norbs=2) lat2 = builder.SimpleSiteFamily(name='bla', norbs=1) lat3 = builder.SimpleSiteFamily(name='dd', norbs=4) cons_law = {lat: np.diag([1, 2]), lat2: 0} syst = builder.Builder( conservation_law=cons_law, time_reversal=( lambda site, p: np.exp(1j * p) * np.identity(site.family.norbs))) syst[lat(1)] = np.identity(2) syst[lat2(1)] = 1 params = dict(p=0) sym = syst.finalized().discrete_symmetry(params=params) for proj, should_be in zip(sym.projectors, np.identity(3)): assert np.allclose(proj.toarray(), should_be.reshape((3, 1))) assert np.allclose(sym.time_reversal.toarray(), np.identity(3)) syst.conservation_law = lambda site, p: cons_law[site.family] sym = syst.finalized().discrete_symmetry(params=params) for proj, should_be in zip(sym.projectors, np.identity(3)): assert np.allclose(proj.toarray(), should_be.reshape((-1, 1))) syst = builder.Builder(conservation_law=np.diag([-1, 1])) syst[lat(1)] = np.identity(2) sym = syst.finalized().discrete_symmetry() for proj, should_be in zip(sym.projectors, np.identity(2)): assert np.allclose(proj.toarray(), should_be.reshape((-1, 1))) syst = builder.Builder(conservation_law=1) syst[lat2(1)] = 0 sym = syst.finalized().discrete_symmetry() [proj] = sym.projectors assert np.allclose(proj.toarray(), [[1]]) syst = kwant.Builder(conservation_law=np.diag([-1, 1, -1, 1])) syst[lat3(0)] = np.eye(4) sym = syst.finalized().discrete_symmetry() p1 = np.zeros((4, 2)) p1[0, 0] = p1[2, 1] = 1 assert np.allclose(sym.projectors[0].toarray(), p1) p2 = np.zeros((4, 2)) p2[1, 0] = p2[3, 1] = 1 assert np.allclose(sym.projectors[1].toarray(), p2) # test parameter passing to conservation_law syst = builder.Builder(conservation_law=lambda site, b: b) syst[lat2(1)] = 0 sym = syst.finalized().discrete_symmetry(params=dict(a=None, b=1)) [proj] = sym.projectors assert np.allclose(proj.toarray(), [[1]])
def test_update(): lat = builder.SimpleSiteFamily() syst = builder.Builder() syst[[lat(0, ), lat(1, )]] = 1 syst[lat(0, ), lat(1, )] = 1 other_syst = builder.Builder() other_syst[[lat(1, ), lat(2, )]] = 2 other_syst[lat(1, ), lat(2, )] = 1 lead0 = builder.Builder(VerySimpleSymmetry(-1)) lead0[lat(0, )] = 1 lead0[(lat(0, ), lat(1, ))] = 1 lead0 = builder.BuilderLead(lead0, [lat(0, )]) syst.leads.append(lead0) lead1 = builder.Builder(VerySimpleSymmetry(1)) lead1[lat(2, )] = 1 lead1[(lat(2, ), lat(1, ))] = 1 lead1 = builder.BuilderLead(lead1, [lat(2, )]) other_syst.leads.append(lead1) syst.update(other_syst) assert syst.leads == [lead0, lead1] expected = sorted([((0, ), 1), ((1, ), 2), ((2, ), 2)]) assert sorted(((s.tag, v) for s, v in syst.site_value_pairs())) == expected expected = sorted([((0, ), (1, ), 1), ((1, ), (2, ), 1)]) assert (sorted(((a.tag, b.tag, v) for (a, b), v in syst.hopping_value_pairs())) == expected)
def test_construction_and_indexing(): # Without symmetry fam = builder.SimpleSiteFamily() sites = [fam(0, 0), fam(0, 1), fam(1, 0)] hoppings = [(fam(0, 0), fam(0, 1)), (fam(0, 1), fam(1, 0)), (fam(1, 0), fam(0, 0))] unknown_hoppings = [(fam(0, 1), fam(7, 8)), (fam(12, 14), fam(0, 1))] check_construction_and_indexing(sites, sites, hoppings, hoppings, unknown_hoppings) # With symmetry sites = [fam(0, 0), fam(1, 1), fam(2, 1), fam(4, 2)] sites_fd = [fam(0, 0), fam(1, 1), fam(0, 1), fam(0, 2)] hoppings = [(fam(0, 0), fam(1, 1)), (fam(1, 1), fam(2, 1)), (fam(2, 1), fam(4, 2)), (fam(4, 2), fam(0, 0))] hoppings_fd = [(fam(0, 0), fam(1, 1)), (fam(1, 1), fam(2, 1)), (fam(0, 1), fam(2, 2)), (fam(0, 2), fam(-4, 0))] unknown_hoppings = [(fam(0, 0), fam(0, 3)), (fam(0, 4), fam(0, 0)), (fam(0, 0), fam(2, 3)), (fam(2, 4), fam(0, 0)), (fam(4, 2), fam(6, 3)), (fam(6, 4), fam(4, 2))] sym = VerySimpleSymmetry(2) check_construction_and_indexing(sites, sites_fd, hoppings, hoppings_fd, unknown_hoppings, sym)
def make_system(): # 1 # / \ # 3-0---2-4-5 6-7 8 syst = builder.Builder() fam = builder.SimpleSiteFamily() syst[(fam(i) for i in range(9))] = None syst[[(fam(0), fam(1)), (fam(1), fam(2)), (fam(2), fam(0))]] = None syst[[(fam(0), fam(3)), (fam(2), fam(4)), (fam(4), fam(5))]] = None syst[fam(6), fam(7)] = None return syst
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)
def check_construction_and_indexing(sites, sites_fd, hoppings, hoppings_fd, unknown_hoppings, sym=None): fam = builder.SimpleSiteFamily() syst = builder.Builder(sym) t, V = 1.0j, 0.0 syst[sites] = V for site in sites: syst[site] = V syst[hoppings] = t for hopping in hoppings: syst[hopping] = t for hopping in unknown_hoppings: raises(KeyError, syst.__setitem__, hopping, t) assert (fam(5), fam(123)) not in syst assert (sites[0], fam(5, 123)) not in syst assert (fam(7, 8), sites[0]) not in syst for site in sites: assert site in syst assert syst[site] == V for hop in hoppings: rev_hop = hop[1], hop[0] assert hop in syst assert rev_hop in syst assert syst[hop] == t assert syst[rev_hop] == t.conjugate() assert syst.degree(sites[0]) == 2 assert (sorted(s for s in syst.neighbors(sites[0])) == sorted( [sites[1], sites[-1]])) del syst[hoppings] assert list(syst.hoppings()) == [] syst[hoppings] = t del syst[sites[0]] assert sorted(tuple(s) for s in syst.sites()) == sorted(sites_fd[1:]) assert (sorted( (a, b) for a, b in syst.hoppings()) == sorted(hoppings_fd[1:-1])) assert (sorted((tuple(site.tag), value) for site, value in syst.site_value_pairs()) == sorted( (tuple(site.tag), syst[site]) for site in syst.sites())) assert (sorted((tuple(a.tag), tuple(b.tag), value) for (a, b), value in syst.hopping_value_pairs()) == sorted( (tuple(a.tag), tuple(b.tag), syst[a, b]) for a, b in syst.hoppings()))
def test_value_equality_and_identity(): m = ta.array([[1, 2], [3j, 4j]]) syst = builder.Builder() fam = builder.SimpleSiteFamily() syst[fam(0)] = m syst[fam(1)] = m assert syst[fam(1)] is m syst[fam(0), fam(1)] = m assert syst[fam(1), fam(0)] == m.transpose().conjugate() assert syst[fam(0), fam(1)] is m syst[fam(1), fam(0)] = m assert syst[fam(0), fam(1)] == m.transpose().conjugate() assert syst[fam(1), fam(0)] is m
def test_hermitian_conjugation(): def f(i, j, arg): i, j = i.tag, j.tag if j[0] == i[0] + 1: return arg * ta.array([[1, 2j], [3 + 1j, 4j]]) else: raise ValueError syst = builder.Builder() fam = builder.SimpleSiteFamily() syst[fam(0)] = syst[fam(1)] = ta.identity(2) syst[fam(0), fam(1)] = f assert syst[fam(0), fam(1)] is f assert isinstance(syst[fam(1), fam(0)], builder.HermConjOfFunc) assert (syst[fam(1), fam(0)](fam(1), fam(0), 2) == syst[fam(0), fam(1)](fam(0), fam(1), 2).conjugate().transpose()) syst[fam(0), fam(1)] = syst[fam(1), fam(0)] assert isinstance(syst[fam(0), fam(1)], builder.HermConjOfFunc) assert syst[fam(1), fam(0)] is f
def test_hamiltonian_evaluation(): def f_onsite(site): return site.tag[0] def f_hopping(a, b): a, b = a.tag, b.tag return complex(a[0] + b[0], a[1] - b[1]) tags = [(0, 0), (1, 1), (2, 2), (3, 3)] edges = [(0, 1), (0, 2), (0, 3), (1, 2)] syst = builder.Builder() fam = builder.SimpleSiteFamily() sites = [fam(*tag) for tag in tags] syst[(fam(*tag) for tag in tags)] = f_onsite syst[((fam(*tags[i]), fam(*tags[j])) for (i, j) in edges)] = f_hopping fsyst = syst.finalized() assert fsyst.graph.num_nodes == len(tags) assert fsyst.graph.num_edges == 2 * len(edges) for i in range(len(tags)): site = fsyst.sites[i] assert site in sites assert fsyst.hamiltonian(i, i) == syst[site](site) for t, h in fsyst.graph: tsite = fsyst.sites[t] hsite = fsyst.sites[h] assert fsyst.hamiltonian(t, h) == syst[tsite, hsite](tsite, hsite) # test when user-function raises errors def onsite_raises(site): raise ValueError() def hopping_raises(a, b): raise ValueError('error message') def test_raising(fsyst, hop): a, b = hop # exceptions are converted to kwant.UserCodeError and we add our message with raises(kwant.UserCodeError) as ctx: fsyst.hamiltonian(a, a) msg = 'Error occurred in user-supplied value function "onsite_raises"' assert msg in ctx.exconly() for hop in [(a, b), (b, a)]: with raises(kwant.UserCodeError) as ctx: fsyst.hamiltonian(*hop) msg = ('Error occurred in user-supplied ' 'value function "hopping_raises"') assert msg in ctx.exconly() # test with finite system new_hop = (fam(-1, 0), fam(0, 0)) syst[new_hop[0]] = onsite_raises syst[new_hop] = hopping_raises fsyst = syst.finalized() hop = tuple(map(fsyst.sites.index, new_hop)) test_raising(fsyst, hop) # test with infinite system inf_syst = kwant.Builder(VerySimpleSymmetry(2)) for k, v in it.chain(syst.site_value_pairs(), syst.hopping_value_pairs()): inf_syst[k] = v inf_fsyst = inf_syst.finalized() hop = tuple(map(inf_fsyst.sites.index, new_hop)) test_raising(inf_fsyst, hop)
def test_bad_keys(): def setitem(key): syst[key] = None fam = builder.SimpleSiteFamily() syst = builder.Builder() failures = [ # Invalid single keys ([syst.__contains__, syst.__getitem__, setitem, syst.__delitem__], [(TypeError, [123, (0, 1), (fam(0), 123), (123, (fam(0)))]), (IndexError, [(fam(0), ), (fam(0), fam(1), fam(2))]), (ValueError, [(fam(0), fam(0)), (fam(2), fam(2))])]), # Hoppings that contain sites that do not belong to the system ([syst.__getitem__, setitem, syst.__delitem__], [(KeyError, [(fam(0), fam(3)), (fam(2), fam(1)), (fam(2), fam(3))])]), # Sequences containing a bad key. ([setitem, syst.__delitem__], [(TypeError, [[fam(0), fam(1), 123], [fam(0), (fam(1), )], [fam(0), (fam(1), fam(2))], [(fam(0), fam(1)), (0, 1)], [(fam(0), fam(1)), (fam(0), 123)], [(fam(0), fam(1)), (123, fam(0))], [(fam(0), fam(1)), fam(2)]]), (IndexError, [[(fam(0), fam(1)), (fam(2), )]]), (ValueError, [[(fam(0), fam(1)), (fam(2), fam(2))], [(fam(0), fam(0)), (fam(1), fam(0))]]), (KeyError, [[(fam(0), fam(1)), (fam(0), fam(3))], [(fam(0), fam(1)), (fam(2), fam(1))], [(fam(1), fam(2)), (fam(0), fam(1))]])]), # Sites that do not belong to the system, also as part of a # sequence ([syst.__delitem__], [(KeyError, [fam(123), [fam(0), fam(123)], [fam(123), fam(1)]])]), # Various things that are not sites present in the system. ([syst.degree, lambda site: list(syst.neighbors(site))], [(TypeError, [ 123, [0, 1, 2], (0, 1), (fam(0), fam(1)), [fam(0), fam(1)], [fam(1), fam(2)], [fam(3), fam(0)] ]), (KeyError, [fam(123)])]) ] for funcs, errors in failures: for error, keys in errors: for key in keys: for func in funcs: syst[[fam(0), fam(1)]] = None syst[fam(0), fam(1)] = None try: raises(error, func, key) except AssertionError: print(func, error, key) raise
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)