Coverage for kwant/builder.py : 93%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# Copyright 2011-2016 Kwant authors. # # This file is part of Kwant. It is subject to the license terms in the file # LICENSE.rst found in the top-level directory of this distribution and at # http://kwant-project.org/license. A list of Kwant authors can be found in # the file AUTHORS.rst at the top-level directory of this distribution and at # http://kwant-project.org/authors.
'HoppingKind', 'Lead', 'BuilderLead', 'SelfEnergyLead', 'ModesLead']
################ Sites and site families
"""A site, member of a `SiteFamily`.
Sites are the vertices of the graph which describes the tight binding system in a `Builder`.
A site is uniquely identified by its family and its tag.
Parameters ---------- family : an instance of `SiteFamily` The 'type' of the site. tag : a hashable python object The unique identifier of the site within the site family, typically a vector of integers.
Raises ------ ValueError If `tag` is not a proper tag for `family`.
Notes ----- For convenience, ``family(*tag)`` can be used instead of ``Site(family, tag)`` to create a site.
The parameters of the constructor (see above) are stored as instance variables under the same names. Given a site ``site``, common things to query are thus ``site.family``, ``site.tag``, and ``site.pos``. """
doc="The site family to which the site belongs.")
def pos(self): """Real space position of the site.
This relies on ``family`` having a ``pos`` method (see `SiteFamily`). """
"""Abstract base class for site families.
Site families are the 'type' of `Site` objects. Within a family, individual sites are uniquely identified by tags. Valid tags must be hashable Python objects, further details are up to the family.
Site families must be immutable and fully defined by their initial arguments. They must inherit from this abstract base class and call its __init__ function providing it with two arguments: a canonical representation and a name. The canonical representation will be returned as the objects representation and must uniquely identify the site family instance. The name is a string used to distinguish otherwise identical site families. It may be empty. ``norbs`` defines the number of orbitals on sites associated with this site family; it may be `None`, in which case the number of orbitals is not specified.
All site families must define the method `normalize_tag` which brings a tag to the standard format for this site family.
Site families that are intended for use with plotting should also provide a method `pos(tag)`, which returns a vector with real-space coordinates of the site belonging to this family with a given tag.
If the ``norbs`` of a site family are provided, and sites of this family are used to populate a `~kwant.builder.Builder`, then the associated Hamiltonian values must have the correct shape. That is, if a site family has ``norbs = 2``, then any on-site terms for sites belonging to this family should be 2x2 matrices. Similarly, any hoppings to/from sites belonging to this family must have a matrix structure where there are two rows/columns. This condition applies equally to Hamiltonian values that are given by functions. If this condition is not satisfied, an error will be raised. """
msg = '<{0} site family {1}{2}>' else:
except AttributeError: return False
# If this raises an AttributeError, we were trying # to compare it to something non-comparable anyway.
@abc.abstractmethod def normalize_tag(self, tag): """Return a normalized version of the tag.
Raises TypeError or ValueError if the tag is not acceptable. """ pass
""" A convenience function.
This function allows to write fam(1, 2) instead of Site(fam, (1, 2)). """ # Catch a likely and difficult to find mistake. raise ValueError('Use site_family(1, 2) instead of ' 'site_family((1, 2))!')
"""A site family used as an example and for testing.
A family of sites tagged by any python objects where object satisfied condition ``object == eval(repr(object))``.
It exists to provide a basic site family that can be used for testing the builder module without other dependencies. It can be also used to tag sites with non-numeric objects like strings should this every be useful.
Due to its low storage efficiency for numbers it is not recommended to use `SimpleSiteFamily` when `kwant.lattice.Monatomic` would also work. """
repr(norbs))
raise RuntimeError() except: raise TypeError('It must be possible to recreate the tag from ' 'its representation.')
"""Verify that the argument is a valid hopping."""
# This check is essential to maintaining the requirement that hoppings must # be tuples. Without it, list "hoppings" would work in some cases # (e.g. with Builder.__contains__). type(hopping).__name__))
# The following check is not strictly necessary (there would be an error # anyway), but the error message would be confusing.
# This check is essential for Builder.__contains__ - without it a builder # would simply "not contain" such invalid hoppings. In other cases it # provides a nicer error message. .format(type(site).__name__))
# This again is an essential check. Without it, builders would accept loop # hoppings. "{0}".format(a))
################ Symmetries
"""Abstract base class for spatial symmetries.
Many physical systems possess a discrete spatial symmetry, which results in special properties of these systems. This class is the standard way to describe discrete spatial symmetries in Kwant. An instance of this class can be passed to a `Builder` instance at its creation. The most important kind of symmetry is translational symmetry, used to define scattering leads.
Each symmetry has a fundamental domain -- a set of sites and hoppings, generating all the possible sites and hoppings upon action of symmetry group elements. A class derived from `Symmetry` has to implement mapping of any site or hopping into the fundamental domain, applying a symmetry group element to a site or a hopping, and a method `which` to determine the group element bringing some site from the fundamental domain to the requested one. Additionally, it has to have a property `num_directions` returning the number of independent symmetry group generators (number of elementary periods for translational symmetry).
A ``ValueError`` must be raised by the symmetry class whenever a symmetry is used together with sites whose site family is not compatible with it. A typical example of this is when the vector defining a translational symmetry is not a lattice vector.
The type of the domain objects as handled by the methods of this class is not specified. The only requirement is that it must support the unary minus operation. The reference implementation of `to_fd()` is hence `self.act(-self.which(a), a, b)`. """
@abc.abstractproperty def num_directions(self): """Number of elementary periods of the symmetry.""" pass
@abc.abstractmethod def which(self, site): """Calculate the domain of the site.
Return the group element whose action on a certain site from the fundamental domain will result in the given ``site``. """ pass
@abc.abstractmethod def act(self, element, a, b=None): """Act with a symmetry group element on a site or hopping.""" pass
"""Map a site or hopping to the fundamental domain.
If ``b`` is None, return a site equivalent to ``a`` within the fundamental domain. Otherwise, return a hopping equivalent to ``(a, b)`` but where the first element belongs to the fundamental domain.
Equivalent to `self.act(-self.which(a), a, b)`. """
"""Tell whether ``site`` lies within the fundamental domain."""
@abc.abstractmethod def subgroup(self, *generators): """Return the subgroup generated by a sequence of group elements.""" pass
@abc.abstractmethod def has_subgroup(self, other): """Test whether `self` has the subgroup `other`...
or, in other words, whether `other` is a subgroup of `self`. The reason why this is the abstract method (and not `is_subgroup`) is that in general it's not possible for a subgroup to know its supergroups.
""" pass
"""A symmetry with a trivial symmetry group."""
return isinstance(other, NoSymmetry)
return not self.__eq__(other)
return 'NoSymmetry()'
def num_directions(self):
raise ValueError('`element` must be empty for NoSymmetry.')
if any(generators): raise ValueError('Generators must be empty for NoSymmetry.') return NoSymmetry(generators)
################ Hopping kinds
"""A pattern for matching hoppings.
An alias exists for this common name: ``kwant.HoppingKind``.
A hopping ``(a, b)`` matches precisely when the site family of ``a`` equals `family_a` and that of ``b`` equals `family_b` and ``(a.tag - b.tag)`` is equal to `delta`. In other words, the matching hoppings have the form: ``(family_a(x + delta), family_b(x))``
Parameters ---------- delta : Sequence of integers The sequence is interpreted as a vector with integer elements. family_a : `~kwant.builder.SiteFamily` family_b : `~kwant.builder.SiteFamily` or ``None`` (default) The default value means: use the same family as `family_a`.
Notes ----- A ``HoppingKind`` is a callable object: When called with a `~kwant.builder.Builder` as sole argument, an instance of this class will return an iterator over all possible matching hoppings whose sites are already present in the system. The hoppings do *not* have to be already present in the system. For example::
kind = kwant.builder.HoppingKind((1, 0), lat) syst[kind(syst)] = 1
Because a `~kwant.builder.Builder` can be indexed with functions or iterables of functions, ``HoppingKind`` instances (or any non-tuple iterables of them, e.g. a list) can be used directly as "wildcards" when setting or deleting hoppings::
kinds = [kwant.builder.HoppingKind(v, lat) for v in [(1, 0), (0, 1)]] syst[kinds] = 1 """
doc="The difference between the tags of the hopping's sites") doc="The family of the first site in the hopping") doc="The family of the second site in the hopping")
else:
'and {} are'.format(family_b) if not same_fams else ' is', 'not compatible with delta={}'.format(delta), )
return '{0}({1}, {2}{3})'.format( self.__class__.__name__, repr(tuple(self.delta)), repr(self.family_a), ', ' + repr(self.family_b) if self.family_a != self.family_b else '')
return '{0}({1}, {2}{3})'.format( self.__class__.__name__, tuple(self.delta), self.family_a, ', ' + str(self.family_b) if self.family_a != self.family_b else '')
################ Support for Hermitian conjugation
""" Calculate the hermitian conjugate of a python object.
If the object is neither a complex number nor a matrix, the original value is returned. In the context of this module, this is the correct behavior for functions. """
"""Proxy returning the hermitian conjugate of the original result."""
################ Leads
"""Abstract base class for leads that can be attached to a `Builder`.
To attach a lead to a builder, append it to the builder's `~Builder.leads` instance variable. See the documentation of `kwant.builder` for the concrete classes of leads derived from this one.
Attributes ---------- interface : sequence of sites
"""
@abc.abstractmethod def finalized(self): """Return a finalized version of the lead.
Returns ------- finalized_lead
Notes ----- The finalized lead must be an object that can be used as a lead in a `kwant.system.FiniteSystem`. It could be an instance of `kwant.system.InfiniteSystem` for example.
The order of sites for the finalized lead must be the one specified in `interface`. """ pass
"""A lead made from a `Builder` with a spatial symmetry.
Parameters ---------- builder : `Builder` The tight-binding system of a lead. It has to possess appropriate symmetry, and it may not contain hoppings between further than neighboring images of the fundamental domain. interface : sequence of `Site` instances Sequence of sites in the scattering region to which the lead is attached.
Attributes ---------- builder : `Builder` The tight-binding system of a lead. interface : list of `Site` instances A sorted list of interface sites.
Notes ----- The hopping from the scattering region to the lead is assumed to be equal to the hopping from a lead unit cell to the next one in the direction of the symmetry vector (i.e. the lead is 'leaving' the system and starts with a hopping).
Every system has an attribute `leads`, which stores a list of `BuilderLead` objects with all the information about the leads that are attached. """
"""Return a `kwant.system.InfiniteSystem` corresponding to the compressed lead.
The order of interface sites is kept during finalization. """
# Check that a modes/selfenergy function has a keyword-only parameter # 'params', or takes '**kwargs'. If not, we wrap it for p in parameters.values()) else: # function conforming to old API: needs wrapping
"""A general lead defined by its self energy.
Parameters ---------- selfenergy_func : function Has the same signature as `selfenergy` (without the ``self`` parameter) and returns the self energy matrix for the interface sites. interface : sequence of `Site` instances """ # we changed the API of 'selfenergy_func' to have a keyword-only # parameter 'params', but we still need to support the old API # XXX: remove this when releasing Kwant 2.0
"""Trivial finalization: the object is returned itself."""
"""A general lead defined by its modes wave functions.
Parameters ---------- modes_func : function Has the same signature as `modes` (without the ``self`` parameter) and returns the modes of the lead as a tuple of `~kwant.physics.PropagatingModes` and `~kwant.physics.StabilizedModes`. interface : sequence of `Site` instances
""" # we changed the API of 'selfenergy_func' to have a keyword-only # parameter 'params', but we still need to support the old API # XXX: remove this when releasing Kwant 2.0
"""Trivial finalization: the object is returned itself."""
stabilized = self.modes(energy, args, params=params)[1] return stabilized.selfenergy()
################ Builder class
# A marker, meaning for hopping (i, j): this value is given by the Hermitian # conjugate the value of the hopping (j, i). Used by Builder and System.
# izip, when given the same iterator twice, turns a sequence into a # sequence of pairs.
"""Return a sequence of ranges for ``sites``.
Here, "ranges" are defined as sequences of sites that have the same site family. Because site families now have a fixed number of orbitals, this coincides with the definition given in `~kwant.system.System`. """ # we shall start a new range of different `SiteFamily`s separately, # even if they happen to contain the same number of orbitals. # can't provide site_ranges if norbs not given # add sentinel to the end
"""A tight binding system defined on a graph.
An alias exists for this common name: ``kwant.Builder``.
This is one of the central types in Kwant. It is used to construct tight binding systems in a flexible way.
The nodes of the graph are `Site` instances. The edges, i.e. the hoppings, are pairs (2-tuples) of sites. Each node and each edge has a value associated with it. The values associated with nodes are interpreted as on-site Hamiltonians, the ones associated with edges as hopping integrals.
To make the graph accessible in a way that is natural within the Python language it is exposed as a *mapping* (much like a built-in Python dictionary). Keys are sites or hoppings. Values are 2d arrays (e.g. NumPy or Tinyarray) or numbers (interpreted as 1 by 1 matrices).
Parameters ---------- symmetry : `Symmetry` or `None` The spatial symmetry of the system. conservation_law : 2D array, dictionary, function, or `None` An onsite operator with integer eigenvalues that commutes with the Hamiltonian. The ascending order of eigenvalues corresponds to the selected ordering of the Hamiltonian subblocks. If a dict is given, it maps from site families to such matrices. If a function is given it must take the same arguments as the onsite Hamiltonian functions of the system and return the onsite matrix. time_reversal : scalar, 2D array, dictionary, function, or `None` The unitary part of the onsite time-reversal symmetry operator. Same format as that of `conservation_law`. particle_hole : scalar, 2D array, dictionary, function, or `None` The unitary part of the onsite particle-hole symmetry operator. Same format as that of `conservation_law`. chiral : 2D array, dictionary, function or `None` The unitary part of the onsite chiral symmetry operator. Same format as that of `conservation_law`.
Notes -----
Values can be also functions that receive the site or the hopping (passed to the function as two sites) and possibly additional arguments and are expected to return a valid value. This allows to define systems quickly, to modify them without reconstructing, and to save memory for many-orbital models.
In addition to simple keys (single sites and hoppings) more powerful keys are possible as well that allow to manipulate multiple sites/hoppings in a single operation. Such keys are internally expanded into a sequence of simple keys by using the method `Builder.expand`. For example, ``syst[general_key] = value`` is equivalent to ::
for simple_key in syst.expand(general_key): syst[simple_key] = value
Builder instances automatically ensure that every hopping is Hermitian, so that if ``builder[a, b]`` has been set, there is no need to set ``builder[b, a]``.
Builder instances can be made to automatically respect a `Symmetry` that is passed to them during creation. The behavior of builders with a symmetry is slightly more sophisticated: all keys are mapped to the fundamental domain of the symmetry before storing them. This may produce confusing results when neighbors of a site are queried.
The method `attach_lead` *works* only if the sites affected by them have tags which are sequences of integers. It *makes sense* only when these sites live on a regular lattice, like the ones provided by `kwant.lattice`.
Attaching a lead manually (without the use of `~Builder.attach_lead`) amounts to creating a `Lead` object and appending it to this list.
.. warning::
If functions are used to set values in a builder with a symmetry, then they must satisfy the same symmetry. There is (currently) no check and wrong results will be the consequence of a misbehaving function.
Attributes ---------- leads : list of `Lead` instances The leads that are attached to the system.
Examples -------- Define a site.
>>> builder[site] = value
Print the value of a site.
>>> print(builder[site])
Define a hopping.
>>> builder[site1, site2] = value
Delete a site.
>>> del builder[site3]
Detach the last lead. (This does not remove the sites that were added to the scattering region by `~Builder.attach_lead`.)
>>> del builder.leads[-1]
"""
particle_hole=None, chiral=None): else:
#### Note on H #### # # This dictionary stores a directed graph optimized for efficient querying # and modification. The nodes are instances of `Site`. # # Each edge, specified by a ``(tail, head)`` pair of nodes, holds an object # as a value. Likewise, each tail which occurs in the graph also holds a # value. (Nodes which only occur as heads are not required to have # values.) Every tail node has to be in the fundamental domain of the # builder's symmetry. # # For a given `tail` site, H[tail] is a list alternately storing # heads and values. (The heads occupy even locations followed by the # values at odd locations.) Each pair of entries thus describes a single # directed edge of the graph. # # The first pair of entries in each list is special: it always # corresponds to a loop edge. (The head is equal to the tail.) This # special edge has two purposes: It is used to store the value # associated with the tail node itself, and it is necessary for the # method getkey_tail which helps to conserve memory by storing equal # node label only once.
# (tail, head) is not present in the system, but tail is. raise KeyError((tail, head)) else: # If already head is missing, we only report this. This way the # behavior is symmetric with regard to tail and head.
else:
# (tail, head) is not present in the system, but tail is. raise KeyError((tail, head)) else: # If already head is missing, we only report this. This way the # behavior is symmetric with regard to tail and head.
# TODO: write a test for this method. """Return a shallow copy of the builder with the symmetry reversed.
This method can be used to attach the same infinite system as lead from two opposite sides. It requires a builder to which an infinite symmetry is associated. """ raise ValueError('System to be reversed may not have leads.')
return bool(self.H)
""" Expand a general key into an iterator over simple keys.
Parameters ---------- key : builder key (see notes) The key to be expanded
Notes ----- Keys are (recursively): * Simple keys: sites or 2-tuples of sites (=hoppings). * Any (non-tuple) iterable of keys, e.g. a list or a generator expression. * Any function that returns a key when passed a builder as sole argument, e.g. a `HoppingKind` instance or the function returned by `~kwant.lattice.Polyatomic.shape`.
This method is internally used to expand the keys when getting or deleting items of a builder (i.e. ``syst[key] = value`` or ``del syst[key]``).
""" # Site instances are also tuples. else: .format(type(key).__name__)) else:
"""Get the value of a single site or hopping."""
else:
"""Tell whether the system contains a site or hopping."""
"""Set a single site.""" else:
"""Set a single hopping."""
# Make sure that we do not waste space by storing multiple instances # of identical sites. else:
# It's important that we have verified that b2 belongs to the system. # Otherwise, we risk ending up with a half-added hopping. # Avoid nested HermConjOfFunc instances. else:
"""Set a single site/hopping or a bunch of them.""" else self._set_hopping)
"""Delete a single site and all associated hoppings.""" type(site).__name__))
else:
"""Delete a single hopping."""
else:
"""Delete a single site/hopping or bunch of them.""" else self._del_hopping)
"""Keep deleting dangling sites until none are left.""" if self._out_degree(site) < 2) else:
"""Return an iterator over all sites and hoppings.""" return chain(self.H, self.hoppings())
"""Return a read-only set over all sites.
The sites that are returned belong to the fundamental domain of the `Builder` symmetry, and are not necessarily the ones that were set initially (but always the equivalent ones). """ except AttributeError: return frozenset(self.H)
"""Return an iterator over all (site, value) pairs."""
"""Return an iterator over all Builder hoppings.
The hoppings that are returned belong to the fundamental domain of the `Builder` symmetry, and are not necessarily the ones that were set initially (but always the equivalent ones). """
"""Return an iterator over all (hopping, value) pairs."""
"""Return an iterator over all dangling sites."""
"""Return the number of neighbors of a site.""" type(site).__name__))
"""Return an iterator over all neighbors of a site.
Technical note: This method respects the symmetry of the builder, i.e. the returned sites are really connected to the given site (and not to its image in the fundamental domain). """ type(site).__name__)) # Optimization for common case.
"""Return the site that is closest to the given position.
This function takes into account the symmetry of the builder. It is assumed that the symmetry is a translational symmetry.
This function executes in a time proportional to the number of sites, so it is not efficient for large builders. It is especially slow for builders with a symmetry, but such systems often contain only a limited number of sites.
""" "pos().\nThe following one does not:\n")
# Determine basis in real space from first site. (The result from # any site would do.) for element in I]
except AttributeError: raise AttributeError(errmsg + str(site.family)) for element in I]
"""Update builder from `other`.
All sites and hoppings of `other`, together with their values, are written to `self`, overwriting already existing sites and hoppings. The leads of `other` are appended to the leads of the system being updated.
This method requires that both builders share the same symmetry. """ or not other.symmetry.has_subgroup(self.symmetry)): raise ValueError("Both builders involved in update() must have " "equal symmetries.")
warnings.warn("The += operator of builders is deprecated. Use " "'Builder.update()' instead.", KwantDeprecationWarning, stacklevel=2) self.update(other) return self
"""Populate builder using another one as a template.
Starting from one or multiple sites, traverse the graph of the template builder and copy sites and hoppings to the target builder. The traversal stops at sites that are already present in the target and on sites that are not inside the provided shape.
This function takes into account translational symmetry. As such, typically the template will have a higher symmetry than the target.
Newly added sites are connected by hoppings to sites that were already present. This facilitates construction of a system by a series of calls to 'fill'.
Parameters ---------- template : `Builder` instance The builder used as the template. The symmetry of the target builder must be a subgroup of the symmetry of the template. shape : callable A boolean function of site returning whether the site should be added to the target builder or not. The shape must be compatible with the symmetry of the target builder. start : `Site` instance or iterable thereof or iterable of numbers The site(s) at which the the flood-fill starts. If start is an iterable of numbers, the starting site will be ``template.closest(start)``. max_sites : positive number The maximal number of sites that may be added before ``RuntimeError`` is raised. Used to prevent using up all memory.
Returns ------- added_sites : list of `Site` objects that were added to the system.
Raises ------ ValueError If the symmetry of the target isn't a subgroup of the template symmetry. RuntimeError If more than `max_sites` sites are to be added. The target builder will be left in an unusable state.
Notes ----- This function uses a flood-fill algorithm. If the template builder consists of disconnected parts, the fill will stop at their boundaries.
"""
# Check that symmetries are commensurate. raise ValueError("Builder symmetry is not a subgroup of the " "template symmetry")
else:
"not in the template builder.", RuntimeWarning, stacklevel=2)
# "Active" are sites (mapped to the target's FD) that have been # verified to lie inside the shape, have been added to the target # (with `None` as value), but yet without their hoppings.
"all starting sites.", RuntimeWarning, stacklevel=2) else: "the desired shape", RuntimeWarning, stacklevel=2)
# Flood-fill on the graph. We work site by site, writing all the # outgoing edges.
"parameter of fill()) added.")
# Make an iterator over head-value-pairs.
# The remaining pairs are the heads and their associated # values.
and head_fd not in new_active): # The 'head' site has not been filled yet. # The 'head' site exists. (It doesn't matter # whether it's in the shape or not.) Fill the # incoming edge as well to balance the hopping. *templ_sym.to_fd(head, tail)) + (other_value,)) else: # There is no site at 'head' and it's # outside the shape.
# Fill the outgoing edge. i = 2 + 2 * old_heads.index(head) hvhv[i] = head hvhv[i + 1] = value else:
# The graph has unbalanced edges: delete it. # Re-raise the exception with an additional message. "exception\noccurred during the execution of fill(): " "see above.")
"""Attach a lead to the builder, possibly adding missing sites.
This method first adds sites from 'lead_builder' until the interface where the lead will attach is "smooth". Then it appends the 'lead_builder' and the interface sites as a `~kwant.builder.BuilderLead` to the 'leads' of this builder.
Parameters ---------- lead_builder : `Builder` with 1D translational symmetry Builder of the lead which has to be attached. origin : `Site` The site which should belong to a domain where the lead should begin. It is used to attach a lead inside the system, e.g. to an inner radius of a ring. add_cells : int Number of complete unit cells of the lead to be added to the system *after* the missing sites have been added.
Returns ------- added_sites : list of `Site` objects that were added to the system.
Raises ------ ValueError If `lead_builder` does not have proper symmetry, has hoppings with range of more than one lead unit cell, or if it is not completely interrupted by the system.
Notes ----- This method is not fool-proof, i.e. if it raises an error, there is no guarantee that the system stayed unaltered.
The system must "interrupt" the lead that is being attached. This means that for each site in the lead that has a hopping to a neighbnoring unit cell there must be at least one site in the system that is an image of the lead site under the action of the lead's translational symmetry. In order to interrupt the lead, the system must contain sites from the same site family as the sites in the lead. Below are three examples of leads being attached to systems::
Successful Successful Unsuccessful ---------- ---------- ------------ Lead System Lead System Lead System x- … o x … x- … | | | | x- … o-o x- … o-o x- … o-o | | | | | | | | | x- … o-o-o x- … o-o-o x- … o-o
The second case succeeds, as even though the top site has no image in the system, because the top site has no hoppings to sites in other unit cells.
Sites may be added to the system when the lead is attached, so that the interface to the lead is "smooth". Below we show the system after having attached a lead. The 'x' symbols in the system indicate the added sites::
Lead System Lead System x- … x-x-o x … x | | | | | | x- … x-o-o x- … x-o-o | | | | | | | | x- … o-o-o x- … o-o-o """ raise ValueError("Leads can only be attached to finite systems.")
raise ValueError('add_cells must be an integer >= 0.')
raise ValueError('Only builders with a 1D symmetry are allowed.')
for hopping in lead_builder.hoppings())
# Automatically increase the period, potentially warn the user. lead_builder.sites(), max_sites=float('inf'))
# Check if site families of the lead are present in the system (catches # a common and a hard to find bug). else: msg = ('Sites with site families {0} do not appear in the system, ' 'hence the system does not interrupt the lead.') raise ValueError(msg.format(tuple(lead_only_families)))
' this lead cannot be attached.')
raise ValueError('Builder does not interrupt the lead,' ' this lead cannot be attached.')
# We start flood-fill from the first domain that doesn't belong to the # system (this one is guaranteed to contain a complete unit cell of the # lead). After flood-fill we remove that domain. max_sites=float('inf'))
# Calculate the interface.
"""Return a finalized (=usable with solvers) copy of the system.
Returns ------- finalized_system : `kwant.builder.FiniteSystem` If there is no symmetry. finalized_system : `kwant.builder.InfiniteSystem` If a symmetry is present.
Notes ----- This method does not modify the Builder instance for which it is called.
Upon finalization, it is implicitly assumed that **every** function assigned as a value to a builder with a symmetry possesses the same symmetry.
Attached leads are also finalized and will be present in the finalized system to be returned.
Currently, only Builder instances without or with a 1D translational `Symmetry` can be finalized. """ else: raise ValueError('Currently, only builders without or with a 1D ' 'translational symmetry can be finalized.')
#### Make translation tables.
#### Make graph. continue
#### Connect leads. # The following line is the whole "payload" of the entire # try-block. # Re-raise any warnings with an additional message and the # proper stacklevel. w = w.message msg = 'When finalizing lead {0}:'.format(lead_nr) warnings.warn(w.__class__(' '.join((msg,) + w.args)), stacklevel=3) # Re-raise the exception with an additional message. except KeyError as e: msg = ("Lead {0} is attached to a site that does not " "belong to the scattering region:\n {1}") raise ValueError(msg.format(lead_nr, e.args[0]))
#### Find parameters taken by all value functions for tail, head in g]
ham in _ham_param_map): # parameters come in the same order as in the function signature
#### Assemble and return result.
""" Finalize this builder instance which has to have exactly a single symmetry direction.
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. """
#### For each site of the fundamental domain, determine whether it has #### neighbors in the previous domain or not. # Tail belongs to fund. domain, head to the next domain. else: # Tail is a fund. domain site not connected to prev. domain.
RuntimeWarning, stacklevel=3)
### Create list of sites and a lookup table # interface must be sorted else: # 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.
'The sites in interface_order do not all ' 'belong to the same lead cell.') else: 'interface site:\n' + str(iface_site)) 'interface_order did not contain all interface sites.') # `interface_order` *must* be sorted, hence `interface` should also
# we previously sorted the interface, so don't sort it again
#### Make graph and extract onsite Hamiltonians. # Head belongs neither to the fundamental domain nor to the # previous domain. Check that it belongs to the next # domain and ignore it otherwise as an edge corresponding # to this one has been added already or will be added. 'are connected by hopping\n{0}.') continue # Head belongs to previous domain. The edge added here # correspond to one left out just above.
#### Extract hoppings. # The tail belongs to the previous domain. Find the # corresponding hopping with the tail in the fund. domain.
#### Find parameters taken by all value functions ham in _ham_param_map): # parameters come in the same order as in the function signature
#### Assemble and return result.
# Protect novice users from confusing error messages if they # forget to finalize their Builder.
def _require_system(*args, **kwargs): """You need a finalized system; Use Builder.finalized() first.""" raise TypeError('You need a finalized system; ' 'use Builder.finalized() first.')
inter_cell_hopping = cell_hamiltonian = precalculated = \ _require_system
################ Finalized systems
'See the upper part of the above backtrace for more information.')
raise ValueError("Conservation law must have integer eigenvalues.") # Avoid appearance of zero eigenvalues for val in sorted(np.unique(eigvals.data))] else:
self._symmetries))
"""Take a symmetry from builder and transfer it to finalized system."""
# Conservation law requires preprocessing to split it into eigenvectors # and eigenvalues.
def vals(site, *args, **kwargs):
def vecs(site, *args, **kwargs):
ta.array(np.diag(np.linalg.eigvalsh(value)))) for family, value in cons_law.items()} ta.array(np.linalg.eigh(value)[1])) for family, value in cons_law.items()}
else: raise e # skip coverage
builder.particle_hole, builder.chiral)]
"""Finalized `Builder` with leads.
Usable as input for the solvers in `kwant.solvers`.
Attributes ---------- sites : sequence ``sites[i]`` is the `~kwant.builder.Site` instance that corresponds to the integer-labeled site ``i`` of the low-level system. The sites are ordered first by their family and then by their tag. id_by_site : dict The inverse of ``sites``; maps from ``i`` to ``sites[i]``. """
"and may not be set with 'params'" .format(', '.join(invalid_params))) except Exception as exc: _raise_user_error(exc, value) else: else: raise ValueError("Parameters {} have default values " "and may not be set with 'params'" .format(', '.join(invalid_params))) except Exception as exc: _raise_user_error(exc, value) else:
"""Finalized infinite system, extracted from a `Builder`.
Attributes ---------- sites : sequence ``sites[i]`` is the `~kwant.builder.Site` instance that corresponds to the integer-labeled site ``i`` of the low-level system. id_by_site : dict The inverse of ``sites``; maps from ``i`` to ``sites[i]``.
Notes ----- In infinite systems ``sites`` consists of 3 parts: sites in the fundamental domain (FD) with hoppings to neighboring cells, sites in the FD with no hoppings to neighboring cells, and sites in FD+1 attached to the FD by hoppings. Each of these three subsequences is individually sorted. """
"and may not be set with 'params'" .format(', '.join(invalid_params))) except Exception as exc: _raise_user_error(exc, value) else: else: raise ValueError("Parameters {} have default values " "and may not be set with 'params'" .format(', '.join(invalid_params))) except Exception as exc: _raise_user_error(exc, value) else:
return self.sites[i].pos
|