def test_symmetry_has_subgroup(): rng = np.random.RandomState(0) ## test whether actual subgroups are detected as such vecs = rng.randn(3, 3) sym1 = lattice.TranslationalSymmetry(*vecs) ns = builder.NoSymmetry() assert ns.has_subgroup(ns) assert sym1.has_subgroup(sym1) assert sym1.has_subgroup(ns) assert sym1.has_subgroup( lattice.TranslationalSymmetry(2 * vecs[0], 3 * vecs[1] + 4 * vecs[2])) assert not lattice.TranslationalSymmetry(*(0.8 * vecs)).has_subgroup(sym1) ## test subgroup creation for dim in range(1, 4): generators = rng.randint(10, size=(dim, 3)) assert sym1.has_subgroup(sym1.subgroup(*generators)) # generators are not linearly independent with raises(ValueError): sym1.subgroup(*rng.randint(10, size=(4, 3))) # generators are not integer sequences with raises(ValueError): sym1.subgroup(*rng.rand(1, 3))
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))