A long time ago Maciej Zwierzycki wrote:
While trying to force Kwant to accept the unit cell of the lead in a particular, connected form, I've encountered somewhat puzzling situation illustrated in the attached piece of code. The described procedure does not make sense physically, but its purpose is to illustrate the behaviour which may possibly (?) lead to problems, at least for newbies like me. ;)
Your problem is not related to a bug, but rather to subtleties of how sites work in Kwant. I will try to explain everything in detail. Perhaps we can come up with ideas how Kwant could be improved to avoid such problems? A site in Kwant always belongs to a site family, i.e. an instance of a class derived from ‘SiteFamiliy’. In fact, a site is just a tuple consisting of a tag and a family to which some custom methods have been added. A site family specify all the properties of the sites that belong to it. A very simple example of a custom site family is shown in the Kwant paper. In practice, almost all site families are instances of the ‘kwant.lattice.Monatomic’ class, which is an abstraction for a Bravais lattice with a single atom basis. It would be possible to create a site family that represents a polyatomic Bravais lattice, but then the tags of such a site family would be a mix of an index for the basis and indices for the actual Bravais lattice. E.g. creating two sites at position (2, 3) that belongs to, respectively, sublattices 0 and 1 would look like this: lat(0, 2, 3) lat(1, 2, 3) Whereas we felt the following to be nicer: lat.a(2, 3) lat.b(2, 3) Note that in the second snippet, ‘lat’ has been created by calling ‘kwant.lattice.honeycomb’ and is an instance of ‘kwant.lattice.Polyatomic’ to which two instance attributes ‘a’ and ‘b’ were added like this lat.a, lat.b = lat.sublattices The object ‘lat’ is *not* a site family. It’s the sublattices that are the site families. ---------------- Two important properties of site families are that they are (effectively) immutable and can be pickled. • Immutability is important so that sites can be used as keys in dictionaries. (This is for example used internally by the builder module, but it’s also handy for users.) • Pickleability is important so that sites and objects containing them (like systems) can be saved to the disk and sent over a network. This comes very handy for parallel computation for example. These two properties have the consequence that two site families that were created with the same parameters are equal. It works just like numbers, or strings, or other immutable objects.
lat_a = kwant.lattice.Monatomic([[1, 0], [0, 1]]) lat_b = kwant.lattice.Monatomic([[1, 0], [0, 1]]) lat_a == lat_b True
(If one needs multiple separate lattices with the same parameters it’s possible to distinguish by using the ‘name’ parameter.)
Let's say I define two honeycomb lattices, differing in the choice of basis, but entirely equivalent (i.e. they overlap)
prime=np.array([[sqrt(3)/2,sqrt(3)],[1.5,0.0]])*a basis_at=np.array([[0.0,0.0],[-0.5,0.5]])*a lat = kwant.lattice.general([prime[:,0],prime[:,1]],[basis_at[:,0],basis_at[:,1]])
and
basis2=np.array([[0.0,sqrt(3)/2],[-0.5,-1.0]])*a lat2 = kwant.lattice.general([prime[:,0],prime[:,1]],[basis2[:,0],basis2[:,1]])
I'm using numpy so that vector algebra works. The rectangular scattering region and the left lead (same width) are populated with "lat". Now I'm adding a few atoms from lat2 to the right edge of the scattering region, e.g. a single hexagon
for i in range (0,1): # changing the range we can generate also the full layer of lat2 sites syst[lat2.sublattices[0](0+2*i,9-i)]=0.0 syst[lat2.sublattices[1](0+2*i,8-i)]=0.0 syst[lat2.sublattices[0](1+2*i,8-i)]=0.0 syst[lat2.sublattices[1](1+2*i,8-i)]=0.0
and then attach the lead, also populated with "lat2". I know, that's not how it's described in tutorial. ;)
If you were to do this with two different monatomic lattices (e.g. a square lattices), you would get an error that the right lead is not stopped by the central region. But in your case the situation is more complicated: Each call to ‘kwant.lattice.general’ returns an instance of ‘Polyatomic’ which is just a collection of monatomic lattices that are the actual site families. In your case, since the first vector of the basis is the same for ‘lat’ and ‘lat2’, but the second differs, we have:
lat.sublattices[0] == lat2.sublattices[0] True lat.sublattices[1] == lat2.sublattices[1] False
One can see this in the plots where the color of a site depends on the site family. Sublattice ‘lat.sublattices[0]’ (which is equal to ‘lat2.sublattices[0]’) is blue, ‘lat.sublattices[1]’ is orange, and ‘lat2.sublattices[1]’ is green.
The filling algorithm generates the system which to naked eye looks like the perfect nanowire. The transmission however is not perfect i.e. T < N (number of modes). If the full layer of lat2 sites is added to the right edge, than everything is as it should be, i.e. perfect transmission.
The naked eye is misguided because there are two distinct site families that occupy the same real space positions, namely the “orange” and the “green” site family. Kwant is happily plotting several sites on top of each other... The function ‘attach_lead’ is only concerned about sites that belong to the families that are present in the lead. (The real space position of a site does not matter here by design.) So, when attaching the lead from the right, it is only concerned about blue and green sites in the central region. Thus, when filling up the scattering region such that it neatly matches the lead unit cell, ‘attach_lead’ happily adds green sites over already existing orange sites and connects them to the surrounding blue sites. The pre-existing orange sites remain dangling with two hoppings only. I attach a plot created by a slightly modified version of your script that is also attached. Observe that in the plot some green triangles are plotted over orange squares.
I'm not sure if it's a bug - I'm doing things not in the manual - but I find it strange. A perfect system, however generated, should lead to perfect transmission. What gives?
Everything is working as designed. However I am always interested to discuss ways in which the design could be improved!
Also I noticed that neighbours() method called for one of the lattices tends to pick up the sites from the other lattice, if they belong to he sublattice generated from (0,-0.5a), i.e. from the common basis. Try commenting out one of the lines 53-54. Is it intentional or not?
This should be clear from the above explanation now, I hope.
It's quite likely that the described situation never arises in real-world situations especially if one does the right thing and pads the interface with the full principal layer before attaching the leads. I've stumbled upon it only thanks to my laziness. But it might also illustrate some fragility of the algorithm, possibly worth eliminating.
In any case I'd be grateful for some illumination. Why isn't the "perfect" wire behaving as it should? Where is the imperfection if it's not visible in the structure?
I think that it was a good decision that we decoupled the real space position of a site from its identity. (In fact, real space position for a site is optional in Kwant.) What is debatable is whether it was a wise choice to make sublattices the site families, especially since the user does not create them directly when making a polyatomic lattice. This could be actually changed, I guess even in a practically backwards-compatible way. Any ideas, observations, questions? Cheers Christoph