Commit b8a912ab authored by Anton Akhmerov's avatar Anton Akhmerov Committed by Christoph Groth
Browse files

introduce immutable SiteGroup, reduce number of SiteGroup classes

parent 09875794
--- original
+++ modified
@@ -16,6 +16,7 @@
# For plotting
from matplotlib import pyplot
+import defs
def make_system(a=1, t=1.0, W=10, r1=10, r2=20):
@@ -82,6 +83,54 @@
return sys
+def make_system_note1(a=1, t=1.0, W=10, r1=10, r2=20):
+ lat = kwant.lattice.Square(a)
+ lat = kwant.lattice.square(a)
+ sys = kwant.Builder()
+ def ring(pos):
+ (x, y) = pos
......@@ -37,7 +37,7 @@
+
+
+def make_system_note2(a=1, t=1.0, W=10, r1=10, r2=20):
+ lat = kwant.lattice.Square(a)
+ lat = kwant.lattice.square(a)
+ sys = kwant.Builder()
+ def ring(pos):
+ (x, y) = pos
......@@ -66,7 +66,7 @@
@@ -95,18 +144,29 @@
smatrix = kwant.solve(sys, energy)
data.append(smatrix.transmission(1, 0))
- pyplot.figure()
+ fig = pyplot.figure()
pyplot.plot(normalized_fluxes, data)
......@@ -85,23 +85,23 @@
+ fig.subplots_adjust(left=0.15, right=0.95, top=0.95, bottom=0.15)
+ fig.savefig("2-ab_ring_result.pdf")
+ fig.savefig("2-ab_ring_result.png", dpi=defs.dpi)
def main():
sys = make_system()
# Check that the system looks as intended.
- kwant.plot(sys)
+ size = (defs.figwidth_in, defs.figwidth_in)
+ kwant.plot(sys, file="2-ab_ring_sys.pdf", fig_size=size, dpi=defs.dpi)
+ kwant.plot(sys, file="2-ab_ring_sys.png", fig_size=size, dpi=defs.dpi)
# Finalize the system.
sys = sys.finalized()
@@ -115,6 +175,15 @@
plot_conductance(sys, energy=0.15, fluxes=[0.01 * i * 3 * 2 * pi
for i in xrange(100)])
+ # Finally, some plots needed for the notes
+ sys = make_system_note1()
+ kwant.plot(sys, file="2-ab_ring_note1.pdf", fig_size=size, dpi=defs.dpi)
......
......@@ -8,7 +8,7 @@ General
.. autosummary::
:toctree: generated/
make_lattice
general
TranslationalSymmetry
MonatomicLattice
PolyatomicLattice
......@@ -18,6 +18,6 @@ Library of lattices
.. autosummary::
:toctree: generated/
Chain
Honeycomb
Square
chain
honeycomb
square
......@@ -22,7 +22,7 @@ From `kwant.lattice`
.. autosummary::
TranslationalSymmetry
make_lattice
general
.. currentmodule:: kwant.plotter
......
......@@ -22,7 +22,7 @@ sys = kwant.Builder()
# Here, we are only working with square lattices
#HIDDEN_BEGIN_suwo
a = 1
lat = kwant.lattice.Square(a)
lat = kwant.lattice.square(a)
#HIDDEN_END_suwo
#HIDDEN_BEGIN_zfvr
......
......@@ -23,7 +23,7 @@ def make_system(a=1, t=1.0, W=10, r1=10, r2=20):
# Start with an empty tight-binding system and a single square lattice.
# `a` is the lattice constant (by default set to 1 for simplicity).
lat = kwant.lattice.Square(a)
lat = kwant.lattice.square(a)
sys = kwant.Builder()
......
......@@ -23,7 +23,7 @@ pot = 0
def make_system(a=1, t=1.0, W=10, L=30, L_well=10):
# Start with an empty tight-binding system and a single square lattice.
# `a` is the lattice constant (by default set to 1 for simplicity.
lat = kwant.lattice.Square(a)
lat = kwant.lattice.square(a)
sys = kwant.Builder()
......
......@@ -32,7 +32,7 @@ sigma_z = tinyarray.array([[1, 0], [0, -1]])
def make_system(a=1, t=1.0, alpha=0.5, e_z=0.08, W=10, L=30):
# Start with an empty tight-binding system and a single square lattice.
# `a` is the lattice constant (by default set to 1 for simplicity).
lat = kwant.lattice.Square(a)
lat = kwant.lattice.square(a)
sys = kwant.Builder()
......
......@@ -16,7 +16,7 @@ from matplotlib import pyplot
#HIDDEN_BEGIN_zxip
def make_lead(a=1, t=1.0, W=10):
# Start with an empty lead with a single square lattice
lat = kwant.lattice.Square(a)
lat = kwant.lattice.square(a)
sym_lead = kwant.TranslationalSymmetry((-a, 0))
lead = kwant.Builder(sym_lead)
......
......@@ -26,7 +26,7 @@ def make_system(a=1, t=1.0, r=10):
# `a` is the lattice constant (by default set to 1 for simplicity).
#HIDDEN_BEGIN_qlyd
lat = kwant.lattice.Square(a)
lat = kwant.lattice.square(a)
sys = kwant.Builder()
......
......@@ -22,8 +22,8 @@ from matplotlib import pyplot
# Define the graphene lattice
sin_30, cos_30 = (1 / 2, sqrt(3) / 2)
#HIDDEN_BEGIN_hnla
graphene = kwant.make_lattice([(1, 0), (sin_30, cos_30)],
[(0, 0), (0, 1 / sqrt(3))])
graphene = kwant.lattice.general([(1, 0), (sin_30, cos_30)],
[(0, 0), (0, 1 / sqrt(3))])
a, b = graphene.sublattices
#HIDDEN_END_hnla
......
......@@ -25,7 +25,7 @@ tau_z = tinyarray.array([[1, 0], [0, -1]])
def make_lead(a=1, t=1.0, mu=0.7, Delta=0.1, W=10):
# Start with an empty lead with a single square lattice
lat = kwant.lattice.Square(a)
lat = kwant.lattice.square(a)
sym_lead = kwant.TranslationalSymmetry((-a, 0))
lead = kwant.Builder(sym_lead)
......
......@@ -18,8 +18,8 @@ def make_system(a=1, W=10, L=10, barrier=1.5, barrierpos=(3, 4),
mu=0.4, Delta=0.1, Deltapos=4, t=1.0):
# Start with an empty tight-binding system and two square lattices,
# corresponding to electron and hole degree of freedom
lat_e = kwant.lattice.Square(a)
lat_h = kwant.lattice.Square(a)
lat_e = kwant.lattice.square(a, name='e')
lat_h = kwant.lattice.square(a, name='h')
#HIDDEN_END_zuuw
#HIDDEN_BEGIN_pqmp
......
......@@ -18,7 +18,7 @@ explicitly here to show how to define a new lattice:
:start-after: #HIDDEN_BEGIN_hnla
:end-before: #HIDDEN_END_hnla
The first argument to the `~kwant.lattice.make_lattice` function is the list of
The first argument to the `~kwant.lattice.general` function is the list of
primitive vectors of the lattice; the second one is the coordinates of basis
atoms. The honeycomb lattice has two basis atoms. Each type of basis atom by
itself forms a regular lattice of the same type as well, and those
......
......@@ -15,8 +15,8 @@ from .version import version as __version__
from .builder import Builder
__all__.append('Builder')
from .lattice import make_lattice, TranslationalSymmetry
__all__.extend(['make_lattice', 'TranslationalSymmetry'])
from .lattice import TranslationalSymmetry
__all__.extend(['TranslationalSymmetry'])
# Make kwant.solvers.default.solve available as kwant.solve.
solve = solvers.default.solve
......
......@@ -77,22 +77,29 @@ class Site(tuple):
def __repr__(self):
return 'Site({0}, {1})'.format(repr(self.group), repr(self.tag))
def __str__(self):
return '{1} of {0}'.format(str(self.group), str(self.tag))
@property
def pos(self):
"""Real space position of the site."""
return self.group.pos(self.tag)
# Counter used to give each newly created group an unique id.
next_group_id = 0
class SiteGroup(object):
"""
Abstract base class for site groups.
A site group is a 'type' of sites. All the site groups must inherit from
this basic one. They have to define the method `verify_tag`.
this basic one. Site groups must be immutable and fully defined by their
initial arguments. One of these arguments should be `name`, used to
distinguish otherwise identical site groups. Every site group must have
an attribute `name` and an attribute `canonical_repr` which uniquely
identifies the group, and is also used for `repr(group)`. For efficiency
`canonical_repr` should be an interned string.
All site groups must define the method `normalize_tag` which brings a tag
to the format standard for this site group.
Site groups which are intended for use with plotting should also provide a
method `pos(tag)`, which returns a vector with real-space coordinates of
......@@ -100,17 +107,26 @@ class SiteGroup(object):
"""
__metaclass__ = abc.ABCMeta
def __init__(self):
global next_group_id
self.group_id = next_group_id
next_group_id += 1
def __repr__(self):
return '<{0} object: Site group {1}>'.format(
self.__class__.__name__, self.group_id)
return self.canonical_repr
def __str__(self):
return '{0} object {1}'.format(self.__class__, self.name)
def __hash__(self):
return self.group_id
return hash(self.canonical_repr)
def __eq__(self, other):
try:
return self.canonical_repr == other.canonical_repr
except AttributeError:
return False
def __neq__(self, other):
try:
return self.canonical_repr != other.canonical_repr
except AttributeError:
return False
@abc.abstractmethod
def normalize_tag(self, tag):
......@@ -146,6 +162,10 @@ class SimpleSiteGroup(SiteGroup):
Due to its low storage efficiency for numbers it is not recommended to use
`SimpleSiteGroup` when `kwant.lattice.MonatomicLattice` would also work.
"""
def __init__(self, name=None):
self.canonical_repr = '{0}({1})'.format(self.__class__, repr(name))
def normalize_tag(self, tag):
tag = tuple(tag)
try:
......@@ -873,9 +893,9 @@ class Builder(object):
def possible_hoppings(self, delta, group_a, group_b):
"""Return all matching possible hoppings between existing sites.
A hopping ``(a, b)`` matches precisely when the site group of ``a`` is
`group_a` and that of ``b`` is `group_b` and ``(a.tag - b.tag)`` is
equal to `delta`.
A hopping ``(a, b)`` matches precisely when the site group of ``a``
equals `group_a` and that of ``b`` equals `group_b` and
``(a.tag - b.tag)`` is equal to `delta`.
In other words, the matching hoppings have the form:
``(group_a(x + delta), group_b(x))``
......@@ -896,7 +916,7 @@ class Builder(object):
symtofd = self.symmetry.to_fd
delta = ta.array(delta, int)
for a in self.H:
if a.group is not group_a:
if a.group != group_a:
continue
b = Site(group_b, a.tag - delta, True)
if symtofd(b) in H:
......
......@@ -38,7 +38,7 @@ def test_rectangle():
for l in [1, 2, 5, 10]:
sys = kwant.Builder()
lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
lat = kwant.lattice.Square()
lat = kwant.lattice.square()
lead[(lat(0, i) for i in xrange(w))] = 0
sys[(lat(j, i) for j in xrange(l) for i in xrange(w))] = 0
for s in [lead, sys]:
......
......@@ -8,7 +8,7 @@
from __future__ import division
__all__ = ['make_lattice', 'TranslationalSymmetry',
__all__ = ['general', 'TranslationalSymmetry',
'PolyatomicLattice', 'MonatomicLattice']
from math import sqrt
......@@ -17,10 +17,9 @@ import tinyarray as ta
from . import builder
def make_lattice(prim_vecs, basis=None):
def general(prim_vecs, basis=None, name=''):
"""
Create a Bravais lattice of any dimensionality, with any number of basis
sites.
Create a Bravais lattice of any dimensionality, with any number of sites.
Parameters
----------
......@@ -28,6 +27,10 @@ def make_lattice(prim_vecs, basis=None):
The primitive vectors of the Bravais lattice.
basis : sequence of floats
The coordinates of the basis sites inside the unit cell.
name : string or sequence of strings
Name of the lattice, or the list of names of all of the sublattices.
If the name of the lattice is given, the names of sublattices (if any)
are obtained by appending their number to the name of the lattice.
Returns
-------
......@@ -40,9 +43,9 @@ def make_lattice(prim_vecs, basis=None):
lattices.
"""
if basis is None:
return MonatomicLattice(prim_vecs)
return MonatomicLattice(prim_vecs, name=name)
else:
return PolyatomicLattice(prim_vecs, basis)
return PolyatomicLattice(prim_vecs, basis, name=name)
class PolyatomicLattice(object):
......@@ -57,6 +60,10 @@ class PolyatomicLattice(object):
Primitive vectors of a Bravais lattice.
basis : sequence of floats
Coordinates of the basis sites inside the unit cell.
name : string or sequence of strings
Name of the lattice, or the list of names of all of the sublattices.
If the name of the lattice is given, the names of sublattices are
obtained by appending their number to the name of the lattice.
Instance Variables
------------------
......@@ -72,9 +79,13 @@ class PolyatomicLattice(object):
-----
"""
def __init__(self, prim_vecs, basis):
def __init__(self, prim_vecs, basis, name=''):
prim_vecs = ta.array(prim_vecs, float)
dim = prim_vecs.shape[1]
if name is None:
name = ''
if isinstance(name, str):
name = [name + str(i) for i in range(len(basis))]
if prim_vecs.shape[0] > dim:
raise ValueError('Number of primitive vectors exceeds '
'the space dimensionality.')
......@@ -82,8 +93,8 @@ class PolyatomicLattice(object):
if basis.shape[1] != dim:
raise ValueError('Basis dimensionality does not match '
'the space dimensionality.')
self.sublattices = [MonatomicLattice(prim_vecs, offset)
for offset in basis]
self.sublattices = [MonatomicLattice(prim_vecs, offset, sname)
for offset, sname in zip(basis, name)]
# Sequence of primitive vectors of the lattice.
self.prim_vecs = prim_vecs
......@@ -162,7 +173,7 @@ class PolyatomicLattice(object):
return ta.dot(int_vec, self.prim_vecs)
class MonatomicLattice(PolyatomicLattice, builder.SiteGroup):
class MonatomicLattice(builder.SiteGroup, PolyatomicLattice):
"""
A site group of sites belonging to a Bravais lattice.
......@@ -175,9 +186,12 @@ class MonatomicLattice(PolyatomicLattice, builder.SiteGroup):
coordinates origin.
"""
def __init__(self, prim_vecs, offset=None):
def __init__(self, prim_vecs, offset=None, name=''):
prim_vecs = ta.array(prim_vecs, float)
dim = prim_vecs.shape[1]
if name is None:
name = ''
self.name = name
if prim_vecs.shape[0] > dim:
raise ValueError('Number of primitive vectors exceeds '
'the space dimensionality.')
......@@ -193,9 +207,35 @@ class MonatomicLattice(PolyatomicLattice, builder.SiteGroup):
self.inv_pv = ta.array(np.linalg.pinv(prim_vecs))
self.offset = offset
builder.SiteGroup.__init__(self)
def short_array_repr(array):
full = ' '.join([i.lstrip() for i in repr(array).split('\n')])
return full[6 : -1]
msg = '{0}({1}, {2}, {3})'
cl = self.__module__ + '.' + self.__class__.__name__
self.canonical_repr = msg.format(cl, short_array_repr(self.prim_vecs),
short_array_repr(self.offset),
repr(self.name))
intern(self.canonical_repr)
self.dim = dim
def short_array_str(array):
full = ', '.join([i.lstrip() for i in str(array).split('\n')])
return full[1 : -1]
if self.name != '':
msg = "MonoatomicLattice {0}, vectors {1}, origin {2}"
self.cached_str = msg.format(self.name,
short_array_str(self.prim_vecs),
short_array_str(self.offset))
else:
msg = "unnamed MonoatomicLattice, vectors {0}, origin [{1}]"
self.cached_str = msg.format(short_array_str(self.prim_vecs),
short_array_str(self.offset))
def __str__(self):
return self.cached_str
def normalize_tag(self, tag):
tag = ta.array(tag, int)
if len(tag) != self.dim:
......@@ -272,7 +312,7 @@ class TranslationalSymmetry(builder.Symmetry):
ValueError
If lattice shape of `gr` cannot have the given `periods`.
"""
if gr in self.site_group_data:
if gr.canonical_repr in self.site_group_data:
raise KeyError('Group already processed, delete it from '
'site_group_data first.')
inv = np.linalg.pinv(gr.prim_vecs)
......@@ -313,7 +353,7 @@ class TranslationalSymmetry(builder.Symmetry):
det_x_inv_m_part = det_x_inv_m[:num_dir, :]
m_part = m[:, :num_dir]
self.site_group_data[gr] = (ta.array(m_part),
self.site_group_data[gr.canonical_repr] = (ta.array(m_part),
ta.array(det_x_inv_m_part), det_m)
@property
......@@ -322,10 +362,10 @@ class TranslationalSymmetry(builder.Symmetry):
def _get_site_group_data(self, group):
try:
return self.site_group_data[group]
return self.site_group_data[group.canonical_repr]
except KeyError:
self.add_site_group(group)
return self.site_group_data[group]
return self.site_group_data[group.canonical_repr]
def which(self, site):
det_x_inv_m_part, det_m = self._get_site_group_data(site.group)[-2:]
......@@ -340,7 +380,7 @@ class TranslationalSymmetry(builder.Symmetry):
raise ValueError(msg.format(self.num_directions, element))
if b is None:
return builder.Site(a.group, a.tag + delta, True)
elif b.group is a.group:
elif b.group == a.group:
return builder.Site(a.group, a.tag + delta, True), \
builder.Site(b.group, b.tag + delta, True)
else:
......@@ -366,39 +406,40 @@ class TranslationalSymmetry(builder.Symmetry):
"""
periods = [[-i for i in j] for j in self.periods]
result = TranslationalSymmetry(*periods)
for gr in self.site_group_data:
m_part, det_x_inv_m_part, det_m = self.site_group_data[gr]
for can_rep in self.site_group_data:
m_part, det_x_inv_m_part, det_m = self.site_group_data[can_rep]
if self.num_directions % 2:
det_m = -det_m
else:
det_x_inv_m_part = -det_x_inv_m_part
m_part = -m_part
result.site_group_data[gr] = (m_part, det_x_inv_m_part, det_m)
result.site_group_data[can_rep] = (m_part, det_x_inv_m_part, det_m)
return result
################ Library of lattices (to be extended)
class Chain(MonatomicLattice):
def __init__(self, a=1):
MonatomicLattice.__init__(self, ((a,),))
self.nearest = [((1,), self, self)]
class Square(MonatomicLattice):
def __init__(self, a=1):
MonatomicLattice.__init__(self, ((a, 0), (0, a)))
self.nearest = [((1, 0), self, self),
((0, 1), self, self)]
class Honeycomb(PolyatomicLattice):
def __init__(self, a=1):
PolyatomicLattice.__init__(
self,
((a, 0), (0.5 * a, 0.5 * a * sqrt(3))),
((0, 0), (0, a / sqrt(3))))
self.a, self.b = self.sublattices
self.nearest = [((0, 0), self.b, self.a),
((0, 1), self.b, self.a),
((-1, 1), self.b, self.a)]
def chain(a=1, name=''):
"""Create a one-dimensional lattice."""
lat = MonatomicLattice(((a,),), name=name)
lat.nearest = [((1,), lat, lat)]
return lat
def square(a=1, name=''):
"""Create a square lattice."""
lat = MonatomicLattice(((a, 0), (0, a)), name=name)
lat.nearest = [((1, 0), lat, lat),
((0, 1), lat, lat)]
return lat
def honeycomb(a=1, name=''):
"""Create a honeycomb lattice."""
lat = PolyatomicLattice(((a, 0), (0.5 * a, 0.5 * a * sqrt(3))),
((0, 0), (0, a / sqrt(3))), name=name)
lat.a, lat.b = lat.sublattices
lat.nearest = [((0, 0), lat.b, lat.a),
((0, 1), lat.b, lat.a),
((-1, 1), lat.b, lat.a)]
return lat
......@@ -12,7 +12,7 @@ try:
except ImportError:
_no_mumps = True
from kwant.lattice import Honeycomb
from kwant.lattice import honeycomb
from kwant import Builder
from nose.tools import assert_equal, assert_true
from numpy.testing.decorators import skipif
......@@ -65,7 +65,7 @@ def test_schur_complement_with_dense():
def test_error_minus_9(r=10):
"""Test if MUMPSError -9 is properly caught by increasing memory"""
graphene = Honeycomb()
graphene = honeycomb()
a, b = graphene.sublattices
def circle(pos):
......
......@@ -12,7 +12,7 @@ from math import pi, cos
def test_band_energies(N=5):
sys = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
lat = kwant.lattice.Square()
lat = kwant.lattice.square()
sys[[lat(0, 0), lat(0, 1)]] = 3
sys[lat(0, 1), lat(0, 0)] = -1
sys[((lat(1, y), lat(0, y)) for y in range(2))] = -1
......
......@@ -13,7 +13,7 @@ import kwant
from kwant.physics.noise import two_terminal_shotnoise
n = 5
chain = kwant.lattice.Chain()
chain = kwant.lattice.chain()
def _twoterminal_system():
np.random.seed(11)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment