From 8074eed3c4a066a335dab743e81aa17ca46da6bb Mon Sep 17 00:00:00 2001 From: Christoph Groth <christoph.groth@cea.fr> Date: Tue, 6 Nov 2012 15:01:14 +0100 Subject: [PATCH] use the term (lead) interface (sites) instead of lead neighbors This new nomenclature avoids the confusion between "lead neighbors" and "site neighbors". --- examples/square.py | 12 +-- examples/tests/test_square.py | 4 +- kwant/builder.py | 121 ++++++++++++++-------------- kwant/graph/tests/test_slicer.py | 4 +- kwant/plotter.py | 4 +- kwant/solvers/common.py | 43 +++++----- kwant/solvers/tests/_test_sparse.py | 6 +- kwant/system.py | 12 +-- kwant/tests/test_builder.py | 10 +-- 9 files changed, 107 insertions(+), 109 deletions(-) diff --git a/examples/square.py b/examples/square.py index 62a02059..64b47c49 100644 --- a/examples/square.py +++ b/examples/square.py @@ -20,10 +20,6 @@ class Lead(object): fermi_energy) class System(kwant.system.FiniteSystem): - # Override abstract attributes. - graph = None - lead_neighbor_seqs = None - def __init__(self, shape, hopping, potential=0, lead_potentials=(0, 0), return_scalars_as_matrix=True): @@ -64,13 +60,13 @@ class System(kwant.system.FiniteSystem): g.add_edges(edges) self.graph = g.compressed() - self.lead_neighbor_seqs = [] + self.lead_interfaces = [] for x in [0, shape[0] - 1]: # We have to use list here, as numpy.array does not understand # generators. - lead_neighbors = list(self.nodeid_from_pos((x, y)) - for y in xrange(shape[1])) - self.lead_neighbor_seqs.append(np.array(lead_neighbors)) + interface = list(self.nodeid_from_pos((x, y)) + for y in xrange(shape[1])) + self.lead_interfaces.append(np.array(interface)) self.leads = [Lead(shape[1], hopping, lead_potentials[i]) for i in range(2)] diff --git a/examples/tests/test_square.py b/examples/tests/test_square.py index e9b020b9..e49d67ff 100644 --- a/examples/tests/test_square.py +++ b/examples/tests/test_square.py @@ -28,9 +28,9 @@ def test_hamiltonian(): def test_self_energy(): sys = square.System((2, 4), 1) - for lead in xrange(len(sys.lead_neighbor_seqs)): + for lead in xrange(len(sys.lead_interfaces)): n_orb = sum( - sys.num_orbitals(site) for site in sys.lead_neighbor_seqs[lead]) + sys.num_orbitals(site) for site in sys.lead_interfaces[lead]) se = sys.self_energy(lead, 0) assert_equal(len(se.shape), 2) assert_equal(se.shape[0], se.shape[1]) diff --git a/kwant/builder.py b/kwant/builder.py index 17b98e5e..ffc8f8ba 100644 --- a/kwant/builder.py +++ b/kwant/builder.py @@ -299,13 +299,13 @@ class Lead(object): Instance Variables ------------------ - neighbors : sequence of sites + interface : sequence of sites """ __metaclass__ = abc.ABCMeta - def check_neighbors(self): - if len(self.neighbors) == 0: - raise ValueError('Lead is not connected (no neighbors).') + def check_interface(self): + if len(self.interface) == 0: + raise ValueError('Lead is not connected (no interface sites).') @abc.abstractmethod def finalized(): @@ -324,7 +324,8 @@ class Lead(object): The method ``self_energy`` of the finalized lead must return a square matrix of appropriate size. - The order of neighbors is assumed to be preserved during finalization. + The order of interface sites is assumed to be preserved during + finalization. """ pass @@ -338,7 +339,7 @@ class BuilderLead(Lead): The tight-binding system of a lead. It has to possess appropriate symmetry, and it may not contain hoppings between further than neighboring lead slices. - neighbors : sequence of `Site` instances + interface : sequence of `Site` instances Sequence of sites in the scattering region to which the lead is attached. @@ -349,24 +350,24 @@ class BuilderLead(Lead): the symmetry vector (i.e. the lead is 'leaving' the system and starts with a hopping). - The given order of neighbors is preserved throughout finalization. + The given order of interface sites is preserved throughout finalization. Every system has an attribute `leads`, which stores a list of `BuilderLead` objects with all the information about the leads that are attached. """ - def __init__(self, builder, neighbors): + def __init__(self, builder, interface): self.builder = builder - self.neighbors = tuple(neighbors) - self.check_neighbors() + self.interface = tuple(interface) + self.check_interface() def finalized(self): """Return a `kwant.system.InfiniteSystem` corresponding to the compressed lead. - The order of neighbors is kept during finalization. + The order of interface sites is kept during finalization. """ - return self.builder._finalized_infinite(self.neighbors) + return self.builder._finalized_infinite(self.interface) class SelfEnergy(Lead): @@ -375,14 +376,14 @@ class SelfEnergy(Lead): Parameters ---------- self_energy_func : function - Function which returns the self energy matrix for the neighbors given - the energy. - neighbors : sequence of `Site` instances + Function which returns the self energy matrix for the interface sites + given the energy. + interface : sequence of `Site` instances """ - def __init__(self, self_energy_func, neighbors): + def __init__(self, self_energy_func, interface): self.self_energy_func = self_energy_func - self.neighbors = tuple(neighbors) - self.check_neighbors() + self.interface = tuple(interface) + self.check_interface() def finalized(self): """Trivial finalization: the object is returned itself.""" @@ -508,9 +509,9 @@ class Builder(object): The behavior of builders with a symmetry is slightly more sophisticated. First of all, it is implicitly assumed throughout kwant that **every** function assigned as a value to a builder with a symmetry possesses the - same symmetry. Secondly, all keys are mapped to the fundamental before - storing them. This may produce confusing results when neighbors of a site - are queried. + same symmetry. Secondly, all keys are mapped to the fundamental domain + before storing them. This may produce confusing results when neighbors of + a site are queried. The methods `possible_hoppings` and `attach_lead` *work* only if the sites affected by them have tags which are sequences of integers. They *make @@ -797,17 +798,17 @@ class Builder(object): if site not in self.H: continue while site: - pneighbors = tuple(self._out_neighbors(site)) - if pneighbors: - assert len(pneighbors) == 1 - pneighbor = pneighbors[0] - self._del_edge(pneighbor, site) - if self._out_degree(pneighbor) > 1: - pneighbor = False + neighbors = tuple(self._out_neighbors(site)) + if neighbors: + assert len(neighbors) == 1 + neighbor = neighbors[0] + self._del_edge(neighbor, site) + if self._out_degree(neighbor) > 1: + neighbor = False else: - pneighbor = False + neighbor = False del self.H[site] - site = pneighbor + site = neighbor def __iter__(self): """Return an iterator over all sites and hoppings.""" @@ -970,7 +971,7 @@ class Builder(object): min_dom = min(all_doms) del all_doms - neighbors = set() + interface = set() added = set() # Initialize flood-fill: create the outermost sites. for site in H: @@ -980,7 +981,7 @@ class Builder(object): if neighbor not in self: self[neighbor] = lead_builder[neighbor] added.add(neighbor) - neighbors.add(neighbor) + interface.add(neighbor) # Do flood-fill. covered = True @@ -1006,7 +1007,7 @@ class Builder(object): self[site_new, site] = lead_builder[site_new, site] added = added2 - self.leads.append(BuilderLead(lead_builder, list(neighbors))) + self.leads.append(BuilderLead(lead_builder, tuple(interface))) return len(self.leads) - 1 def finalized(self): @@ -1059,7 +1060,7 @@ class Builder(object): #### Connect leads. finalized_leads = [] - lead_neighbor_seqs = [] + lead_interfaces = [] for lead_nr, lead in enumerate(self.leads): try: finalized_leads.append(lead.finalized()) @@ -1067,8 +1068,8 @@ class Builder(object): msg = 'Problem finalizing lead {0}:' e.args = (' '.join((msg.format(lead_nr),) + e.args),) raise - lns = [id_by_site[neighbor] for neighbor in lead.neighbors] - lead_neighbor_seqs.append(np.array(lns)) + interface = [id_by_site[isite] for isite in lead.interface] + lead_interfaces.append(np.array(interface)) #### Assemble and return result. result = FiniteSystem() @@ -1078,24 +1079,24 @@ class Builder(object): result.hoppings = [self._get_edge(sites[tail], sites[head]) for tail, head in g] result.onsite_hamiltonians = [self.H[site][1] for site in sites] - result.lead_neighbor_seqs = lead_neighbor_seqs + result.lead_interfaces = lead_interfaces result.symmetry = self.symmetry return result - def _finalized_infinite(self, order_of_neighbors=None): + def _finalized_infinite(self, interface_order=None): """ Finalize this builder instance which has to have exactly a single symmetry direction. - If order_of_neighbors is not set, the order of the neighbors in the - finalized system will be arbitrary. If order_of_neighbors is set to a - sequence of neighbor sites, this order will be kept. + If interface_order is not set, the order of the interface sites in the + finalized system will be arbitrary. If interface_order is set to a + sequence of interface sites, this order will be kept. """ sym = self.symmetry assert sym.num_directions == 1 #### For each site of the fundamental domain, determine whether it has - #### neighbors or not. + #### neighbors in the previous domain or not. lsites_with = [] # Fund. domain sites with neighbors in prev. dom lsites_without = [] # Remaining sites of the fundamental domain for tail in self.H: # Loop over all sites of the fund. domain. @@ -1116,42 +1117,42 @@ class Builder(object): ### Create list of sites and a lookup table minus_one = ta.array((-1,)) plus_one = ta.array((1,)) - if order_of_neighbors is None: - neighbors = [sym.act(minus_one, s) for s in lsites_with] + if interface_order is None: + interface = [sym.act(minus_one, s) for s in lsites_with] else: - shift = ta.array((-sym.which(order_of_neighbors[0])[0] - 1,)) + shift = ta.array((-sym.which(interface_order[0])[0] - 1,)) lsites_with_set = set(lsites_with) lsites_with = [] - neighbors = [] - for out_of_place_neighbor in order_of_neighbors: - # Shift the neighbor domain before the fundamental domain. - # That's the right place for the neighbors of a lead to be, but - # the neighbors in order_of_neighbors might live in a different + interface = [] + for shifted_iface_site in interface_order: + # Shift the interface domain before the fundamental domain. + # That's the right place for the interface of a lead to be, but + # the sites of interface_order might live in a different # domain. - neighbor = sym.act(shift, out_of_place_neighbor) - lsite = sym.act(plus_one, neighbor) + iface_site = sym.act(shift, shifted_iface_site) + lsite = sym.act(plus_one, iface_site) try: lsites_with_set.remove(lsite) except KeyError: - if (-sym.which(out_of_place_neighbor)[0] - 1,) != shift: + if (-sym.which(shifted_iface_site)[0] - 1,) != shift: raise ValueError( - 'The sites in order_of_neighbors do not all ' + 'The sites in interface_order do not all ' 'belong to the same lead slice.') else: - raise ValueError('A site in order_of_neighbors is ' - 'not a neighbor:\n' + str(neighbor)) - neighbors.append(neighbor) + raise ValueError('A site in interface_order is not an ' + 'interface site:\n' + str(iface_site)) + interface.append(iface_site) lsites_with.append(lsite) if lsites_with_set: raise ValueError( - 'order_of_neighbors did not contain all neighbors.') + 'interface_order did not contain all interface sites.') del lsites_with_set - sites = lsites_with + lsites_without + neighbors + sites = lsites_with + lsites_without + interface del lsites_with del lsites_without - del neighbors + del interface id_by_site = {} for site_id, site in enumerate(sites): id_by_site[site] = site_id diff --git a/kwant/graph/tests/test_slicer.py b/kwant/graph/tests/test_slicer.py index bacec81c..e9ba6c76 100644 --- a/kwant/graph/tests/test_slicer.py +++ b/kwant/graph/tests/test_slicer.py @@ -41,8 +41,8 @@ def test_rectangle(): fsys = sys.finalized() slices = slicer.slice(fsys.graph, - fsys.lead_neighbor_seqs[0], - fsys.lead_neighbor_seqs[1]) + fsys.lead_interfaces[0], + fsys.lead_interfaces[1]) # In the rectangle case, the slicing is very constricted and # we know that all slices must have the same shape. diff --git a/kwant/plotter.py b/kwant/plotter.py index 1135cdfc..46ccdd31 100644 --- a/kwant/plotter.py +++ b/kwant/plotter.py @@ -277,7 +277,7 @@ def iterate_lead_sites_builder(syst, lead_copies): if not isinstance(lead, builder.BuilderLead): continue sym = lead.builder.symmetry - shift = sym.which(lead.neighbors[0]) + 1 + shift = sym.which(lead.interface[0]) + 1 for i in xrange(lead_copies): for site in lead.builder.sites(): @@ -289,7 +289,7 @@ def iterate_lead_hoppings_builder(syst, lead_copies): if not isinstance(lead, builder.BuilderLead): continue sym = lead.builder.symmetry - shift = sym.which(lead.neighbors[0]) + 1 + shift = sym.which(lead.interface[0]) + 1 for i in xrange(lead_copies): for site1, site2 in lead.builder.hoppings(): diff --git a/kwant/solvers/common.py b/kwant/solvers/common.py index 44dc9548..d488bc48 100644 --- a/kwant/solvers/common.py +++ b/kwant/solvers/common.py @@ -135,10 +135,10 @@ class SparseSolver(object): splhsmat = getattr(sp, self.lhsformat + '_matrix') sprhsmat = getattr(sp, self.rhsformat + '_matrix') - if not sys.lead_neighbor_seqs: + if not sys.lead_interfaces: raise ValueError('System contains no leads.') - lhs, norb = sys.hamiltonian_submatrix( - sparse=True, return_norb=True)[:2] + lhs, norb = sys.hamiltonian_submatrix(sparse=True, + return_norb=True)[:2] lhs = getattr(lhs, 'to' + self.lhsformat)() lhs = lhs - energy * sp.identity(lhs.shape[0], format=self.lhsformat) @@ -146,7 +146,8 @@ class SparseSolver(object): if np.any(abs((lhs - lhs.T.conj()).data) > 1e-13): raise ValueError('System Hamiltonian is not Hermitian.') - offsets = np.zeros(norb.shape[0] + 1, int) + offsets = np.empty(norb.shape[0] + 1, int) + offsets[0] = 0 offsets[1 :] = np.cumsum(norb) # Process the leads, generate the eigenvector matrices and lambda @@ -155,7 +156,7 @@ class SparseSolver(object): kept_vars = [] rhs = [] lead_info = [] - for leadnum, lead_neighbors in enumerate(sys.lead_neighbor_seqs): + for leadnum, interface in enumerate(sys.lead_interfaces): lead = sys.leads[leadnum] if isinstance(lead, system.InfiniteSystem) and not force_realspace: h = lead.slice_hamiltonian() @@ -189,21 +190,21 @@ class SparseSolver(object): # Construct a matrix of 1's that translates the # inter-slice hopping to a proper hopping # from the system to the lead. - neighbors = np.r_[tuple(np.arange(offsets[i], offsets[i + 1]) - for i in lead_neighbors)] - coords = np.r_[[np.arange(neighbors.size)], [neighbors]] - tmp = sp.csc_matrix((np.ones(neighbors.size), coords), - shape=(neighbors.size, lhs.shape[0])) + iface_orbs = np.r_[tuple(slice(offsets[i], offsets[i + 1]) + for i in interface)] + coords = np.r_[[np.arange(iface_orbs.size)], [iface_orbs]] + transf = sp.csc_matrix((np.ones(iface_orbs.size), coords), + shape=(iface_orbs.size, lhs.shape[0])) if svd is not None: - v_sp = sp.csc_matrix(svd[2].T.conj()) * tmp - vdaguout_sp = tmp.T * sp.csc_matrix(np.dot(svd[2] * svd[1], - u_out)) + v_sp = sp.csc_matrix(svd[2].T.conj()) * transf + vdaguout_sp = transf.T * \ + sp.csc_matrix(np.dot(svd[2] * svd[1], u_out)) lead_mat = - ulinv_out else: - v_sp = tmp - vdaguout_sp = tmp.T * sp.csc_matrix(np.dot(v.T.conj(), - u_out)) + v_sp = transf + vdaguout_sp = transf.T * sp.csc_matrix(np.dot(v.T.conj(), + u_out)) lead_mat = - ulinv_out lhs = sp.bmat([[lhs, vdaguout_sp], [v_sp, lead_mat]], @@ -211,10 +212,10 @@ class SparseSolver(object): if leadnum in in_leads and nprop > 0: if svd: - vdaguin_sp = tmp.T * sp.csc_matrix( + vdaguin_sp = transf.T * sp.csc_matrix( -np.dot(svd[2] * svd[1], u_in)) else: - vdaguin_sp = tmp.T * sp.csc_matrix( + vdaguin_sp = transf.T * sp.csc_matrix( -np.dot(v.T.conj(), u_in)) # defer formation of the real matrix until the proper @@ -226,8 +227,8 @@ class SparseSolver(object): else: sigma = lead.self_energy(energy) lead_info.append(sigma) - indices = np.r_[tuple(range(offsets[i], offsets[i + 1]) for i - in lead_neighbors)] + indices = np.r_[tuple(slice(offsets[i], offsets[i + 1]) + for i in interface)] assert sigma.shape == 2 * indices.shape y, x = np.meshgrid(indices, indices) sig_sparse = splhsmat((sigma.flat, [x.flat, y.flat]), @@ -321,7 +322,7 @@ class SparseSolver(object): expensive and can be less stable. """ - n = len(sys.lead_neighbor_seqs) + n = len(sys.lead_interfaces) if in_leads is None: in_leads = range(n) if out_leads is None: diff --git a/kwant/solvers/tests/_test_sparse.py b/kwant/solvers/tests/_test_sparse.py index ed3aeb20..d95eb21c 100644 --- a/kwant/solvers/tests/_test_sparse.py +++ b/kwant/solvers/tests/_test_sparse.py @@ -229,10 +229,10 @@ def test_tricky_singular_hopping(solve): lead = kwant.Builder(kwant.TranslationalSymmetry([(4, 0)])) lead.default_site_group = system.default_site_group = square - neighbors = [] + interface = [] for i in xrange(n): site = square(-1, i) - neighbors.append(site) + interface.append(site) system[site] = 0 for j in xrange(4): lead[j, i] = 0 @@ -245,7 +245,7 @@ def test_tricky_singular_hopping(solve): lead[(j, i), (j+1, i)] = -1 del lead[(1, 0), (2, 0)] - system.leads.append(kwant.builder.BuilderLead(lead, neighbors)) + system.leads.append(kwant.builder.BuilderLead(lead, interface)) fsys = system.finalized() s = solve(fsys, -1.3)[0] diff --git a/kwant/system.py b/kwant/system.py index f2d130ab..9f64c36f 100644 --- a/kwant/system.py +++ b/kwant/system.py @@ -60,21 +60,21 @@ class FiniteSystem(System): leads : sequence of lead objects Each lead object has to provide at least a method ``self_energy(energy)``. - lead_neighbor_seqs : sequence of sequences of integers + lead_interfaces : sequence of sequences of integers Each sub-sequence contains the indices of the system sites to which the lead is connected. Notes ----- - The length of `leads` must be equal to the length of `lead_neighbor_seqs`. + The length of `leads` must be equal to the length of `lead_interfaces`. For lead ``n``, the method leads[n].self_energy must return a square matrix whose size is ``sum(self.num_orbitals(neighbor) for neighbor in - self.lead_neighbor_seqs[n])``. + self.lead_interfaces[n])``. Often, the elements of `leads` will be instances of `InfiniteSystem`. If - this is the case for lead ``n``, the sites ``lead_neighbor_seqs[n]`` match - the first ``len(lead_neighbor_seqs[n])`` sites of the InfiniteSystem. + this is the case for lead ``n``, the sites ``lead_interfaces[n]`` match + the first ``len(lead_interfaces[n])`` sites of the InfiniteSystem. """ __metaclass__ = abc.ABCMeta @@ -100,7 +100,7 @@ class InfiniteSystem(System): previous slice. They are included so that hoppings between slices can be represented. The N sites of the previous slice correspond to the first `N` sites of the fully included slice. When an InfiniteSystem is used as a - lead, `N` acts also as the number of neighbors to which it must be + lead, `N` acts also as the number of interface sites to which it must be connected. The drawing shows three slices of an infinite system. Each slice consists diff --git a/kwant/tests/test_builder.py b/kwant/tests/test_builder.py index c078ea7d..d162d720 100644 --- a/kwant/tests/test_builder.py +++ b/kwant/tests/test_builder.py @@ -288,8 +288,8 @@ def test_finalization(): sys.leads.append(builder.BuilderLead( lead, (builder.Site(sg, n) for n in neighbors))) fsys = sys.finalized() - assert_equal(len(fsys.lead_neighbor_seqs), 1) - assert_equal([fsys.site(i).tag for i in fsys.lead_neighbor_seqs[0]], + assert_equal(len(fsys.lead_interfaces), 1) + assert_equal([fsys.site(i).tag for i in fsys.lead_interfaces[0]], neighbors) # Add a hopping to the lead which couples two next-nearest slices and check @@ -442,13 +442,13 @@ def test_attach_lead(): sys[(0,)] = 1 sys.attach_lead(lead0) assert_equal(len(list(sys.sites())), 3) - assert_equal(set(sys.leads[0].neighbors), set([gr(-1), gr(0)])) + assert_equal(set(sys.leads[0].interface), set([gr(-1), gr(0)])) sys[(-10,)] = sys[(-11,)] = 0 sys.attach_lead(lead0) - assert_equal(set(sys.leads[1].neighbors), set([gr(-10), gr(-11)])) + assert_equal(set(sys.leads[1].interface), set([gr(-10), gr(-11)])) assert_equal(len(list(sys.sites())), 5) sys.attach_lead(lead0, gr(-5)) - assert_equal(set(sys.leads[0].neighbors), set([gr(-1), gr(0)])) + assert_equal(set(sys.leads[0].interface), set([gr(-1), gr(0)])) sys.finalized() -- GitLab