slow code to setup hoppings
Dear Colleagues, Imagine, I have two different 2D lattices in a heterostructure and want to set up interlayer hoppings between the close-by atoms. I solve this problem in the way presented below. This works, but to my surprise it works so slowly that it became a bottle-neck of my whole computation. Is there a way to improve the code below? (I suspect, it may be the tag comparison that slows down the thing, but I am not sure) def connect(sys,crit): for site1, site2 in it.product(sys.sites(), repeat=2): if crit(site1, site2): yield (site1, site2) def critInterlayer(site1,site2): ## gamma1 hopping integral diff = site1.pos-site2.pos [x,y] = diff if (abs(x)+abs(y)<0.1) and (site1.tag!=site2.tag): return True else: return False sys[connect(sys,critInterlayer)]=hopping Best wishes, Sergey
Hi Sergey, Dear Colleagues,
Imagine, I have two different 2D lattices in a heterostructure and want to set up interlayer hoppings between the close-by atoms. I solve this problem in the way presented below. This works, but to my surprise it works so slowly that it became a bottle-neck of my whole computation. Is there a way to improve the code below? (I suspect, it may be the tag comparison that slows down the thing, but I am not sure)
def connect(sys,crit): for site1, site2 in it.product(sys.sites(), repeat=2): if crit(site1, site2): yield (site1, site2)
This loop will scale as O(N^2), so the first thing I would do is to try and cut down the number of sites N that you are comparing. For example, given that the sites are on different lattices, you could first create iterators that iterate over only the sites in each lattice independently: lat_a_sites = (s for s in sys.sites() if s.family == lat_a) lat_b_sites = (s for s in sys.sites() if s.family == lat_b) pairs_of_sites = it.product(lat_a_sites, lat_b_sites): ... This will already give you a fourfold speedup. If you can put in any other information that will allow you to reduce the number of sites that you compare (e.g. if your system is two 3D slabs, then only use sites "near" the interface) I would then optimize the comparison in the following way: def crit(site1, site2): return tinyarray.abs(site1.pos - site2.pos) < 0.1 sites_to_join = filter(pairs_of_sites, crit) sys[sites_to_join] = hopping Let us know how this goes, Happy Kwanting, Joe
Whoops, I was a bit too hasty! in fact `filter` takes the filtering function first and the iterator to filter second, so sites_to_join = filter(pairs_of_sites, crit) should be sites_to_join = filter(crit, pairs_of_sites) Happy Kwanting, Joe
Thank you, Joseph! Your first advice was sufficient to make it 100 times faster. I strongly suspect that site.tag comparison was a very time-consuming operation. For the benefit of other users, I will add a subtlety that to arrange similar criterion-based hoppings for wires one also needs to compare with sites shifted by wire symmetry: e.g. sym = kwant.TranslationalSymmetry([1, 0]) def connectlead12(sys,crit,sym): ###only interlayer hoppings are included lat1 = (s for s in sys.sites() if s.family == lat) lat2 = (s for s in sys.sites() if s.family == lat2) pairs_of_sites = it.product(lat1, lat2) for site1, site2 in pairs_of_sites: if crit(site1, site2): yield (site1, site2) site2 = sym.act([1],site2) # act with the symmetry if crit(site1, site2): yield (site1, site2) Best wishes, Sergey On 25/05/16 15:12, Joseph Weston wrote:
Hi Sergey,
Dear Colleagues, Imagine, I have two different 2D lattices in a heterostructure and want to set up interlayer hoppings between the close-by atoms. I solve this problem in the way presented below. This works, but to my surprise it works so slowly that it became a bottle-neck of my whole computation. Is there a way to improve the code below? (I suspect, it may be the tag comparison that slows down the thing, but I am not sure)
def connect(sys,crit): for site1, site2 in it.product(sys.sites(), repeat=2): if crit(site1, site2): yield (site1, site2)
This loop will scale as O(N^2), so the first thing I would do is to try and cut down the number of sites N that you are comparing. For example, given that the sites are on different lattices, you could first create iterators that iterate over only the sites in each lattice independently:
lat_a_sites = (s for s in sys.sites() if s.family == lat_a) lat_b_sites = (s for s in sys.sites() if s.family == lat_b) pairs_of_sites = it.product(lat_a_sites, lat_b_sites): ...
This will already give you a fourfold speedup. If you can put in any other information that will allow you to reduce the number of sites that you compare (e.g. if your system is two 3D slabs, then only use sites "near" the interface)
I would then optimize the comparison in the following way:
def crit(site1, site2): return tinyarray.abs(site1.pos - site2.pos) < 0.1
sites_to_join = filter(pairs_of_sites, crit) sys[sites_to_join] = hopping
Let us know how this goes,
Happy Kwanting,
Joe
Hi Joseph, With carefully specifying the information at hand I can get a good speedup. Still, a perfect solution would be a function that quickly finds a site on the regular lattice that is nearest to a given coordinate point (without cycling over sites). Is such function available? Just a further comment: site.family should be compared with monoatomic lattice. So, in general, one compares it with a list of sublattices for graphene-type stuff. Best wishes, Sergey On 25/05/16 15:12, Joseph Weston wrote:
Hi Sergey,
Dear Colleagues, Imagine, I have two different 2D lattices in a heterostructure and want to set up interlayer hoppings between the close-by atoms. I solve this problem in the way presented below. This works, but to my surprise it works so slowly that it became a bottle-neck of my whole computation. Is there a way to improve the code below? (I suspect, it may be the tag comparison that slows down the thing, but I am not sure)
def connect(sys,crit): for site1, site2 in it.product(sys.sites(), repeat=2): if crit(site1, site2): yield (site1, site2)
This loop will scale as O(N^2), so the first thing I would do is to try and cut down the number of sites N that you are comparing. For example, given that the sites are on different lattices, you could first create iterators that iterate over only the sites in each lattice independently:
lat_a_sites = (s for s in sys.sites() if s.family == lat_a) lat_b_sites = (s for s in sys.sites() if s.family == lat_b) pairs_of_sites = it.product(lat_a_sites, lat_b_sites): ...
This will already give you a fourfold speedup. If you can put in any other information that will allow you to reduce the number of sites that you compare (e.g. if your system is two 3D slabs, then only use sites "near" the interface)
I would then optimize the comparison in the following way:
def crit(site1, site2): return tinyarray.abs(site1.pos - site2.pos) < 0.1
sites_to_join = filter(pairs_of_sites, crit) sys[sites_to_join] = hopping
Let us know how this goes,
Happy Kwanting,
Joe
Hi Sergey,
Is http://kwant-project.org/doc/1/reference/generated/kwant.lattice.Monatomic#k...
something like you need?
Best,
Anton
On Wed, May 25, 2016 at 5:30 PM, Sergey Slizovskiy
Hi Joseph, With carefully specifying the information at hand I can get a good speedup.
Still, a perfect solution would be a function that quickly finds a site on the regular lattice that is nearest to a given coordinate point (without cycling over sites). Is such function available?
Just a further comment: site.family should be compared with monoatomic lattice. So, in general, one compares it with a list of sublattices for graphene-type stuff.
Best wishes, Sergey
On 25/05/16 15:12, Joseph Weston wrote:
Hi Sergey,
Dear Colleagues, Imagine, I have two different 2D lattices in a heterostructure and want to set up interlayer hoppings between the close-by atoms. I solve this problem in the way presented below. This works, but to my surprise it works so slowly that it became a bottle-neck of my whole computation. Is there a way to improve the code below? (I suspect, it may be the tag comparison that slows down the thing, but I am not sure)
def connect(sys,crit): for site1, site2 in it.product(sys.sites(), repeat=2): if crit(site1, site2): yield (site1, site2)
This loop will scale as O(N^2), so the first thing I would do is to try and cut down the number of sites N that you are comparing. For example, given that the sites are on different lattices, you could first create iterators that iterate over only the sites in each lattice independently:
lat_a_sites = (s for s in sys.sites() if s.family == lat_a) lat_b_sites = (s for s in sys.sites() if s.family == lat_b) pairs_of_sites = it.product(lat_a_sites, lat_b_sites): ...
This will already give you a fourfold speedup. If you can put in any other information that will allow you to reduce the number of sites that you compare (e.g. if your system is two 3D slabs, then only use sites "near" the interface)
I would then optimize the comparison in the following way:
def crit(site1, site2): return tinyarray.abs(site1.pos - site2.pos) < 0.1
sites_to_join = filter(pairs_of_sites, crit) sys[sites_to_join] = hopping
Let us know how this goes,
Happy Kwanting,
Joe
Hi Anton, It's ALMOST what I need. But I need not the coordinates to be returned but a list of site objects. Can it be done easily? Below is a way it would work IF site objects will be returned: def ClothestConnect(sys,sublattice1,sublattice2,crit): lat1sites = (s for s in sys.sites() if s.family == sublattice1) for site1 in lat1sites: for site2 in sublattice2.n_closest(site1.pos, n=1): if crit(site1, site2): yield (site1, site2) Best wishes, Sergey On 25/05/16 16:33, Anton Akhmerov wrote:
Hi Sergey,
Is http://kwant-project.org/doc/1/reference/generated/kwant.lattice.Monatomic#k... something like you need?
Best, Anton
On Wed, May 25, 2016 at 5:30 PM, Sergey Slizovskiy
wrote: Hi Joseph, With carefully specifying the information at hand I can get a good speedup.
Still, a perfect solution would be a function that quickly finds a site on the regular lattice that is nearest to a given coordinate point (without cycling over sites). Is such function available?
Just a further comment: site.family should be compared with monoatomic lattice. So, in general, one compares it with a list of sublattices for graphene-type stuff.
Best wishes, Sergey
On 25/05/16 15:12, Joseph Weston wrote:
Hi Sergey,
Dear Colleagues, Imagine, I have two different 2D lattices in a heterostructure and want to set up interlayer hoppings between the close-by atoms. I solve this problem in the way presented below. This works, but to my surprise it works so slowly that it became a bottle-neck of my whole computation. Is there a way to improve the code below? (I suspect, it may be the tag comparison that slows down the thing, but I am not sure)
def connect(sys,crit): for site1, site2 in it.product(sys.sites(), repeat=2): if crit(site1, site2): yield (site1, site2)
This loop will scale as O(N^2), so the first thing I would do is to try and cut down the number of sites N that you are comparing. For example, given that the sites are on different lattices, you could first create iterators that iterate over only the sites in each lattice independently:
lat_a_sites = (s for s in sys.sites() if s.family == lat_a) lat_b_sites = (s for s in sys.sites() if s.family == lat_b) pairs_of_sites = it.product(lat_a_sites, lat_b_sites): ...
This will already give you a fourfold speedup. If you can put in any other information that will allow you to reduce the number of sites that you compare (e.g. if your system is two 3D slabs, then only use sites "near" the interface)
I would then optimize the comparison in the following way:
def crit(site1, site2): return tinyarray.abs(site1.pos - site2.pos) < 0.1
sites_to_join = filter(pairs_of_sites, crit) sys[sites_to_join] = hopping
Let us know how this goes,
Happy Kwanting,
Joe
It's ALMOST what I need. But I need not the coordinates to be returned but a list of site objects.
If my memory doesn't ail me, the returned are the lattice coordinates, so to create a site from those you just need to feed them to the site family. Anton
Can it be done easily? Below is a way it would work IF site objects will be returned:
def ClothestConnect(sys,sublattice1,sublattice2,crit): lat1sites = (s for s in sys.sites() if s.family == sublattice1) for site1 in lat1sites: for site2 in sublattice2.n_closest(site1.pos, n=1): if crit(site1, site2): yield (site1, site2)
Best wishes, Sergey
On 25/05/16 16:33, Anton Akhmerov wrote:
Hi Sergey,
Is http://kwant-project.org/doc/1/reference/generated/kwant.lattice.Monatomic#k... something like you need?
Best, Anton
On Wed, May 25, 2016 at 5:30 PM, Sergey Slizovskiy
wrote: Hi Joseph, With carefully specifying the information at hand I can get a good speedup.
Still, a perfect solution would be a function that quickly finds a site on the regular lattice that is nearest to a given coordinate point (without cycling over sites). Is such function available?
Just a further comment: site.family should be compared with monoatomic lattice. So, in general, one compares it with a list of sublattices for graphene-type stuff.
Best wishes, Sergey
On 25/05/16 15:12, Joseph Weston wrote:
Hi Sergey,
Dear Colleagues, Imagine, I have two different 2D lattices in a heterostructure and want to set up interlayer hoppings between the close-by atoms. I solve this problem in the way presented below. This works, but to my surprise it works so slowly that it became a bottle-neck of my whole computation. Is there a way to improve the code below? (I suspect, it may be the tag comparison that slows down the thing, but I am not sure)
def connect(sys,crit): for site1, site2 in it.product(sys.sites(), repeat=2): if crit(site1, site2): yield (site1, site2)
This loop will scale as O(N^2), so the first thing I would do is to try and cut down the number of sites N that you are comparing. For example, given that the sites are on different lattices, you could first create iterators that iterate over only the sites in each lattice independently:
lat_a_sites = (s for s in sys.sites() if s.family == lat_a) lat_b_sites = (s for s in sys.sites() if s.family == lat_b) pairs_of_sites = it.product(lat_a_sites, lat_b_sites): ...
This will already give you a fourfold speedup. If you can put in any other information that will allow you to reduce the number of sites that you compare (e.g. if your system is two 3D slabs, then only use sites "near" the interface)
I would then optimize the comparison in the following way:
def crit(site1, site2): return tinyarray.abs(site1.pos - site2.pos) < 0.1
sites_to_join = filter(pairs_of_sites, crit) sys[sites_to_join] = hopping
Let us know how this goes,
Happy Kwanting,
Joe
Thanks to Anton and Joseph, Here is a working final solution: (changing n to higher values will allow for more long-range hopping) def ClothestConnect(sys,sublattice1,sublattice2,crit): lat1sites = [s for s in sys.sites() if s.family == sublattice1] lat2sites = [s for s in sys.sites() if s.family == sublattice2] for site1 in lat1sites: for site2c in sublattice2.n_closest(site1.pos, n=1): site2=sublattice2(*site2c) if crit(site1, site2) and (site2 in lat2sites): yield (site1, site2) Best wishes, Sergey
participants (3)
-
Anton Akhmerov
-
Joseph Weston
-
Sergey Slizovskiy