I need to calculate a system with a variable number of 2D lattices. So, the pseudo code should look like:
for i in xrange(2,100): # Form a system with (i) number of lattices, with hoppings that depend on (i) in between the lattices # Calculate stuff, such as the transmission amplitude from lead f of lattice j to lead g of lattice k (j, k <= i) # plot calculated stuff as a function of i
It seems that you could generate some lattices like so:
lattices = [kwant.lattice.square(name='lattice_%d' %i) for i in xrange (N)]
# intra-lattice hamiltonian for i, lat in enumerate(lattices): sys[(lat(x, y) for x in ... for y in ...)] = onsite(i) sys[lat.neighbors()] = intra_lattice_hopping(i)
# inter-lattice hamiltonian for i, (lat_from, lat_to) in enumerate(zip(lattices, lattices[1:])): hoppings = (lat_to(x, y), lat_from(x, y) for x in ... for y in ...) sys[hoppings] = inter_lattice_hopping(i, i+1)
which is impossible because a) lattice definitions can only take in realspace coordinates and b) the function on the right side has to have two sites as its first two arguments and the rest will be provided in the solver part of the code.
We can sidestep this issue by having the "onsite", "intra_lattice_hopping" and "inter_lattice_hopping" functions *return functions themselves*:
def inner_onsite(site_i, *args): return lat_index # depends on "lat_index"
The point is that the inner function can use the value of "lat_index", even though when the inner function actually gets called (inside the Kwant solver, when the Hamiltonian is evaluated) the "lat_index" variable has long gone out of scope. This is a technique called a closure .
Hope that answers your question