def test_line(): """1D shape with 1D lattice""" model = pb.Model(examples.chain_lattice(a=1), pb.line(0, 4.5)) assert model.system.num_sites == 4 model = pb.Model(examples.chain_lattice(a=1), pb.line([0, -0.5], [5, 0.5])) assert model.system.num_sites == 6
def test_hopping_generator(): """Generated next-nearest hoppings should produce the same result as the builtin lattice""" from scipy.spatial import cKDTree @pb.hopping_generator("tnn_test", energy=graphene.t_nn) def next_nearest(x, y, z): pos = np.stack([x, y, z], axis=1) dmin = graphene.a * 0.95 dmax = graphene.a * 1.05 kdtree = cKDTree(pos) coo = kdtree.sparse_distance_matrix(kdtree, dmax).tocoo() idx = coo.data > dmin return coo.row[idx], coo.col[idx] @pb.onsite_energy_modifier def onsite_offset(energy): return energy + 3 * graphene.t_nn model = pb.Model(graphene.monolayer(), next_nearest, onsite_offset, graphene.hexagon_ac(1)) expected = pb.Model(graphene.monolayer(2), graphene.hexagon_ac(1)) assert pytest.fuzzy_equal(model.hamiltonian, expected.hamiltonian) @pb.hopping_generator("t_new", energy=1.0) def bad_generator(): """Different array lengths""" return [0, 1, 2], [0, 1] model = pb.Model(graphene.monolayer(), pb.primitive(3, 3), bad_generator) with pytest.raises(RuntimeError) as excinfo: model.eval() assert "the number of `from` and `to` indices must be equal" in str( excinfo.value)
def test_multiorbital_hamiltonian(): """For multi-orbital lattices the Hamiltonian size is larger than the number of sites""" def lattice(): lat = pb.Lattice([1]) lat.add_sublattices(("A", [0], [[1, 3j], [0, 2]])) lat.register_hopping_energies({ "t22": [[0, 1], [2, 3]], "t11": 1, # incompatible hopping - it's never used so it shouldn't raise any errors }) lat.add_hoppings(([1], "A", "A", "t22")) return lat model = pb.Model(lattice(), pb.primitive(3)) h = model.hamiltonian.toarray() assert model.system.num_sites == 3 assert h.shape[0] == 6 assert pytest.fuzzy_equal(h, h.T.conjugate()) assert pytest.fuzzy_equal(h[:2, :2], h[-2:, -2:]) assert pytest.fuzzy_equal(h[:2, :2], [[1, 3j], [-3j, 2]]) assert pytest.fuzzy_equal(h[:2, 2:4], [[0, 1], [2, 3]]) @pb.onsite_energy_modifier def onsite(energy, x, sub_id): return 3 * energy + sub_id.eye * 0 * x @pb.hopping_energy_modifier def hopping(energy): return 2 * energy model = pb.Model(lattice(), pb.primitive(3), onsite, hopping) h = model.hamiltonian.toarray() assert model.system.num_sites == 3 assert h.shape[0] == 6 assert pytest.fuzzy_equal(h, h.T.conjugate()) assert pytest.fuzzy_equal(h[:2, :2], h[-2:, -2:]) assert pytest.fuzzy_equal(h[:2, :2], [[3, 9j], [-9j, 6]]) assert pytest.fuzzy_equal(h[:2, 2:4], [[0, 2], [4, 6]]) assert pytest.fuzzy_equal(h[2:4, 4:6], [[0, 2], [4, 6]]) def lattice_with_zero_diagonal(): lat = pb.Lattice([1]) lat.add_sublattices(("A", [0], [[0, 3j], [0, 0]])) return lat model = pb.Model(lattice_with_zero_diagonal(), pb.primitive(3)) h = model.hamiltonian.toarray() assert model.system.num_sites == 3 assert h.shape[0] == 6 assert pytest.fuzzy_equal(h, h.T.conjugate()) assert pytest.fuzzy_equal(h[:2, :2], h[-2:, -2:]) assert pytest.fuzzy_equal(h[:2, :2], [[0, 3j], [-3j, 0]])
def test_primitive(): """The primitive shape can be positioned using the lattice origin""" model = pb.Model(graphene.monolayer(), pb.primitive(2, 2)) assert model.system.num_sites == 8 assert np.isclose(model.system.x.min(), -1.5 * graphene.a, rtol=1e-3) assert np.isclose(model.system.y.min(), -2 * graphene.a_cc, rtol=1e-3) model = pb.Model( graphene.monolayer().with_offset( [0.5 * graphene.a, 0.5 * graphene.a_cc]), pb.primitive(2, 2)) assert model.system.num_sites == 8 assert np.isclose(model.system.x.min(), -graphene.a, rtol=1e-3) assert np.isclose(model.system.y.min(), -1.5 * graphene.a_cc, rtol=1e-3)
def test_hopping_buffer(): """The energy passed to hopping modifiers is buffered, but users should not be aware of it""" def lattice(): lat = pb.Lattice([1, 0], [0, 1]) lat.add_sublattices(("A", [0, 0], [0, 0, 0, 0])) lat.register_hopping_energies({ "t44": [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]] }) lat.add_hoppings(([1, 0], "A", "A", "t44"), ([0, 1], "A", "A", "t44")) return lat capture = {} @pb.hopping_energy_modifier def check_buffer(energy, hop_id): capture.setdefault(hop_id, []) capture[hop_id] += [energy.copy()] energy[0] = 99 return energy model = pb.Model(lattice(), pb.primitive(3000, 2), check_buffer) assert model.system.num_sites == 6000 assert model.hamiltonian.shape[0] == 24000 energies = capture["t44"] assert len(energies) >= 2 assert energies[0].shape == (6250, 4, 4) for energy in energies: assert np.argwhere(energy == 99).size == 0
def test_structure_map_plot(compare_figure): model = pb.Model(graphene.monolayer(), pb.rectangle(0.8)) structure_map = model.structure_map(model.system.x * model.system.y) with compare_figure() as chk: structure_map.plot(site_radius=(0.03, 0.05)) assert chk.passed
def test_ldos_sublattice(): """LDOS for A and B sublattices should be antisymmetric for graphene with a mass term""" model = pb.Model(graphene.monolayer(), graphene.hexagon_ac(10), graphene.mass_term(1)) kpm = pb.chebyshev.kpm(model) a, b = (kpm.calc_ldos(np.linspace(-5, 5, 50), 0.1, [0, 0], sub) for sub in ('A', 'B')) assert pytest.fuzzy_equal(a.ldos, b.ldos[::-1], rtol=1e-3, atol=1e-6)
def test_complex_multiorbital_hamiltonian(): def checkerboard_lattice(delta, t): lat = pb.Lattice(a1=[1, 0], a2=[0, 1]) lat.add_sublattices(('A', [0, 0], -delta), ('B', [1 / 2, 1 / 2], delta)) lat.add_hoppings( ([0, 0], 'A', 'B', t), ([0, -1], 'A', 'B', t), ([-1, 0], 'A', 'B', t), ([-1, -1], 'A', 'B', t), ) return lat hopp_t = np.array([[2 + 2j, 3 + 3j], [4 + 4j, 5 + 5j]]) # multi-orbital hopping onsite_en = np.array([[1, 1j], [-1j, 1]]) # onsite energy model = pb.Model(checkerboard_lattice(onsite_en, hopp_t), pb.translational_symmetry(True, True)) h = model.hamiltonian.toarray() assert model.system.num_sites == 2 assert h.shape[0] == 4 assert pytest.fuzzy_equal(h, h.T.conjugate()) # check if Hermitian assert pytest.fuzzy_equal( h[:2, :2], -h[-2:, -2:]) # onsite energy on A and B is opposite assert pytest.fuzzy_equal(h[:2, 2:4], 4 * hopp_t) # hopping A <-> B is 4 * hopp_t
def test_dos(params, baseline, plot_if_fails): configurations = [ { 'matrix_format': "ELL", 'optimal_size': False, 'interleaved': False }, { 'matrix_format': "ELL", 'optimal_size': True, 'interleaved': True }, ] model = pb.Model(*params) kernel = pb.lorentz_kernel() strategies = [ pb.kpm(model, kernel=kernel, silent=True, **c) for c in configurations ] energy = np.linspace(0, 2, 25) results = [kpm.calc_dos(energy, broadening=0.15) for kpm in strategies] expected = results[0].with_data( baseline(results[0].data.astype(np.float32))) for i in range(len(results)): plot_if_fails(results[i], expected, 'plot', label=i) for result in results: assert pytest.fuzzy_equal(result, expected, rtol=1e-3, atol=1e-6)
def factory(v1, v2, energy=np.linspace(0, 0.1, 10)): model = pb.Model(graphene.monolayer(), graphene.hexagon_ac(side_width=15), pb.constant_potential(v1), pb.constant_potential(v2)) kpm = pb.greens.kpm(model) return kpm.deferred_ldos(energy, broadening=0.15, position=[0, 0])
def test_api(): model = pb.Model(graphene.monolayer(), pb.primitive(2, 2)) system = model.system idx = system.num_sites // 2 assert idx == system.find_nearest(system.xyz[idx]) assert idx == system.find_nearest(system.xyz[idx], 'B') assert system.find_nearest([0, 0], 'A') != system.find_nearest([0, 0], 'B') with pytest.raises(IndexError) as excinfo: system.find_nearest([0, 0], 'invalid_sublattice') assert "There is no Site named" in str(excinfo.value) assert np.allclose(system.expanded_positions.x, system.positions.x) s = pb.Model(group6_tmd.monolayer_3band("MoS2"), pb.primitive(2, 2)).system assert s.expanded_positions.x.size == s.positions.x.size * 3
def test_hamiltonian_submatrix_sites(): """The `to_sites` and `from_sites` arguments are not supported""" kwant_sys = pb.Model(graphene.monolayer(), pb.rectangle(1, 1)).tokwant() with pytest.raises(RuntimeError) as excinfo: kwant_sys.hamiltonian_submatrix(to_sites=1, from_sites=1) assert "not supported" in str(excinfo.value)
def test_warnings(): """Extra arguments and ignored by pybinding -- warn users""" kwant_sys = pb.Model(graphene.monolayer(), pb.rectangle(1, 1)).tokwant() with pytest.warns(UserWarning): kwant_sys.hamiltonian_submatrix(sparse=True, args=(1, )) with pytest.warns(UserWarning): kwant_sys.hamiltonian_submatrix(sparse=True, params=dict(v=1))
def test_structure_map_plot(compare_figure): model = pb.Model(graphene.monolayer(), pb.rectangle(0.8)) system = model.system data = np.arange(system.num_sites) structure_map = pb.results.StructureMap.from_system(data, system) with compare_figure() as chk: structure_map.plot_structure(site_radius=(0.03, 0.05), cbar_props=False) assert chk.passed
def test_structure_map_plot(compare_figure): model = pb.Model(graphene.monolayer(), pb.rectangle(0.8)) data = [3, 11, 19, 26, 5, 13, 21, 0, 7, 15, 23, 2, 9, 17, 10, 18, 25, 4, 12, 20, 27, 6, 14, 22, 1, 8, 16, 24] structure_map = model.structure_map(data) with compare_figure() as chk: structure_map.plot(site_radius=(0.03, 0.05)) assert chk.passed
def test_sites(): model = pb.Model(graphene.monolayer(), pb.primitive(2, 2)) system = model.system sites = pb.system.Sites(system.positions, system.sublattices) idx = system.num_sites // 2 assert idx == sites.find_nearest(system.xyz[idx]) assert idx == sites.find_nearest(system.xyz[idx], system.sublattices[idx]) assert sites.find_nearest([0, 0], 'A') != sites.find_nearest([0, 0], 'B')
def test_site_and_hopping_interaction(): """Add a new row of sites and connect them just like the rest of the lattice""" d = 1.0 v = 1.5 t = 1.0 def square_lattice(): lat = pb.Lattice(a1=[d, 0], a2=[0, d]) lat.add_sublattices(("A", [0, 0], v)) lat.add_hoppings(([0, 1], "A", "A", t), ([1, 0], "A", "A", t)) return lat @pb.site_generator(name="B", energy=v) def edge_sites(system): edge_atoms = system.count_neighbors() < 4 x, y, z = (v[edge_atoms] for v in system.positions) top_edge_only = np.isclose(y, y.max()) x, y, z = (v[top_edge_only] for v in (x, y, z)) y += d return x, y, z @pb.hopping_generator(name="t_edge", energy=t) def edge_hoppings(system, y): new_sites = system.sub == "B" edge_atoms = np.logical_and(system.sub != "B", system.count_neighbors() < 4) top_edge_only = np.logical_and(edge_atoms, np.isclose(y, y[edge_atoms].max())) return new_sites, top_edge_only @pb.hopping_generator(name="t_edge2", energy=t) def edge_hoppings2(system): edge_idx = np.flatnonzero(system.sub == "B") to_idx = edge_idx[1:] from_idx = edge_idx[:-1] return to_idx, from_idx model = pb.Model(square_lattice(), pb.primitive(6, 4), edge_sites, edge_hoppings, edge_hoppings2) expected = pb.Model(square_lattice(), pb.primitive(6, 5)) assert pytest.fuzzy_equal(model.hamiltonian, expected.hamiltonian)
def factory(v, energy=np.linspace(0, 0.1, 10)): model = pb.Model(graphene.monolayer(), graphene.hexagon_ac(side_width=15), pb.constant_potential(v)) kpm = pb.kpm(model, kernel=pb.lorentz_kernel()) return kpm.deferred_ldos(energy, broadening=0.15, position=[0, 0], sublattice="B")
def test_structure_map_plot(compare_figure): import matplotlib.pyplot as plt model = pb.Model(graphene.monolayer(), pb.rectangle(0.8)) structure_map = model.structure_map(model.system.x * model.system.y) with compare_figure() as chk: structure_map.plot(site_radius=(0.03, 0.05)) plt.gca().set_aspect("equal", "datalim") assert chk.passed
def test_optimized_hamiltonian(): """Currently available only in internal interface""" from pybinding import _cpp model = pb.Model(graphene.monolayer(), graphene.hexagon_ac(10)) h = model.hamiltonian oh = _cpp.OptimizedHamiltonian(model.raw_hamiltonian, 0) assert oh.matrix.shape == h.shape assert oh.sizes[-1] == h.shape[0] assert len(oh.indices) == h.shape[0]
def model(): def ring(inner_radius, outer_radius): def contains(x, y, _): r = np.sqrt(x**2 + y**2) return np.logical_and(inner_radius < r, r < outer_radius) return pb.FreeformShape(contains, width=[2 * outer_radius, 2 * outer_radius]) return pb.Model(graphene.monolayer(), ring(3, 5))
def make_model(v0=0): model = pb.Model( graphene.monolayer().with_min_neighbors(1), pb.rectangle(length, width), potential_barrier(v0), ) model.attach_lead( -1, pb.line([-length / 2, -width / 2], [-length / 2, width / 2])) model.attach_lead( +1, pb.line([length / 2, -width / 2], [length / 2, width / 2])) return model
def square_model(width=2, height=3): def square_lattice(d=1, t=1): lat = pb.Lattice(a1=[d, 0], a2=[0, d]) lat.add_sublattices(('A', [0, 0])) lat.add_hoppings( ([0, 1], 'A', 'A', -t), ([1, 0], 'A', 'A', -t), ) return lat return pb.Model(square_lattice(), pb.rectangle(width, height))
def test_kpm_reuse(): """KPM should return the same result when a single object is used for multiple calculations""" model = pb.Model(graphene.monolayer(), graphene.hexagon_ac(10)) kpm = pb.chebyshev.kpm(model) energy = np.linspace(-5, 5, 50) broadening = 0.1 for position in [0, 0], [6, 0]: actual = kpm.calc_ldos(energy, broadening, position) expected = pb.chebyshev.kpm(model).calc_ldos(energy, broadening, position) assert pytest.fuzzy_equal(actual, expected, rtol=1e-3, atol=1e-6)
def test_add_sublattice_alias(mock_lattice): c_position = [0, 9] mock_lattice.add_one_sublattice('c', c_position, alias='a') model = pb.Model(mock_lattice) c_index = model.system.find_nearest(c_position) assert mock_lattice['c'] != mock_lattice['a'] assert model.system.sublattices[c_index] == mock_lattice['a'] with pytest.raises(IndexError) as excinfo: mock_lattice.add_one_sublattice('d', [0, 0], alias='bad_name') assert "There is no sublattice named 'bad_name'" in str(excinfo.value)
def test_api(): model = pb.Model(graphene.monolayer(), pb.primitive(2, 2)) system = model.system idx = system.num_sites // 2 assert idx == system.find_nearest(system.xyz[idx]) assert idx == system.find_nearest(system.xyz[idx], 'B') assert system.find_nearest([0, 0], 'A') != system.find_nearest([0, 0], 'B') with pytest.raises(IndexError) as excinfo: system.find_nearest([0, 0], 'invalid_sublattice') assert "There is no sublattice" in str(excinfo.value)
def test_hopping_generator(): """Generated next-nearest hoppings should produce the same result as the builtin lattice""" from scipy.spatial import cKDTree @pb.hopping_generator("tnn_test", energy=graphene.t_nn) def next_nearest(x, y, z): pos = np.stack([x, y, z], axis=1) dmin = graphene.a * 0.95 dmax = graphene.a * 1.05 kdtree = cKDTree(pos) coo = kdtree.sparse_distance_matrix(kdtree, dmax).tocoo() idx = coo.data > dmin return coo.row[idx], coo.col[idx] @pb.onsite_energy_modifier def onsite_offset(energy): return energy + 3 * graphene.t_nn model = pb.Model(graphene.monolayer(), next_nearest, onsite_offset, graphene.hexagon_ac(1)) expected = pb.Model(graphene.monolayer(2), graphene.hexagon_ac(1)) assert pytest.fuzzy_equal(model.hamiltonian, expected.hamiltonian)
def test_hamiltonian_submatrix_orbitals(lattice, norb): """Return the number of orbitals at each site in addition to the Hamiltonian""" model = pb.Model(lattice, pb.rectangle(1, 1)) kwant_sys = model.tokwant() matrix, to_norb, from_norb = kwant_sys.hamiltonian_submatrix( sparse=True, return_norb=True) assert matrix.shape == model.hamiltonian.shape assert to_norb.size == model.system.num_sites assert from_norb.size == model.system.num_sites assert np.all(to_norb == norb) assert np.all(from_norb == norb)
def test_multiorbital_onsite(): def multi_orbital_lattice(): lat = pb.Lattice([1, 0], [0, 1]) tau_z = np.array([[1, 0], [0, -1]]) tau_x = np.array([[0, 1], [1, 0]]) lat.add_sublattices(("A", [0, 0], tau_z + 2 * tau_x), ("B", [0, 0.1], 0.5), ("C", [0, 0.2], [1, 2, 3])) lat.add_hoppings(([0, -1], "A", "A", 3 * tau_z), ([1, 0], "A", "A", 3 * tau_z), ([0, 0], "B", "C", [[2, 3, 4]])) return lat capture = {} @pb.onsite_energy_modifier def onsite(energy, x, y, z, sub_id): capture[sub_id] = [v.copy() for v in (energy, x, y, z)] return energy def assert_onsite(name, **expected): energy, x, y, z = capture[name] assert energy.shape == expected["shape"] expected_energy = np.array(expected["energy"]) for index in np.ndindex(*expected_energy.shape): expected_slice = np.full(energy.shape[-1], expected_energy[index]) assert pytest.fuzzy_equal(energy[index], expected_slice) assert pytest.fuzzy_equal(x, expected["x"]) assert pytest.fuzzy_equal(y, expected["y"]) assert pytest.fuzzy_equal(z, expected["z"]) model = pb.Model(multi_orbital_lattice(), pb.rectangle(2, 1), onsite) assert model.system.num_sites == 6 assert model.hamiltonian.shape[0] == 12 assert_onsite("A", shape=(2, 2, 2), energy=[[1, 2], [2, -1]], x=[0, 1], y=[0, 0], z=[0, 0]) assert_onsite("B", shape=(2,), energy=[0.5], x=[0, 1], y=[0.1, 0.1], z=[0, 0]) assert_onsite("C", shape=(3, 3, 2), energy=[[1, 0, 0], [0, 2, 0], [0, 0, 3]], x=[0, 1], y=[0.2, 0.2], z=[0, 0])
def test_api(ring_model): with pytest.raises(RuntimeError) as excinfo: ring_model.attach_lead(0, pb.line(0, 0)) assert "Lead direction must be one of" in str(excinfo.value) for direction in [3, -3]: with pytest.raises(RuntimeError) as excinfo: ring_model.attach_lead(direction, pb.line(0, 0)) assert "not valid for a 2D lattice" in str(excinfo.value) with pytest.raises(RuntimeError) as excinfo: pb.Model(examples.chain_lattice()).attach_lead(2, pb.line(0, 0)) assert "Attaching leads to 1D lattices is not supported" in str( excinfo.value)