+ Store sites in the fundamental domain only
+ Compute and store the symmetry element with each term
Here we continue to build the hopping terms from the graph, however
when extending to handle >1D translational symmetry we will need
to query the Builder directly. We could in principle already do that
at this stage, and it would mean that less has to change later.
... | ... |
@@ -1915,8 +1915,11 @@ class _VectorizedFinalizedBuilderMixin(_FinalizedBuilderMixin): |
1915 | 1915 |
if not is_onsite: |
1916 | 1916 |
from_family = self.site_arrays[from_which].family |
1917 | 1917 |
from_tags = self.site_arrays[from_which].tags |
1918 |
- from_site_array = SiteArray(from_family, from_tags[from_off]) |
|
1919 |
- site_arrays = self.symmetry.to_fd(to_site_array, from_site_array) |
|
1918 |
+ from_site_array = self.symmetry.act( |
|
1919 |
+ term.symmetry_element, |
|
1920 |
+ SiteArray(from_family, from_tags[from_off]) |
|
1921 |
+ ) |
|
1922 |
+ site_arrays = (to_site_array, from_site_array) |
|
1920 | 1923 |
|
1921 | 1924 |
# Construct args from params |
1922 | 1925 |
if params: |
... | ... |
@@ -2301,9 +2304,15 @@ def _make_onsite_terms(builder, sites, site_arrays, term_offset): |
2301 | 2304 |
err if isinstance(err, Exception) else None |
2302 | 2305 |
for err in onsite_term_parameters |
2303 | 2306 |
] |
2307 |
+ |
|
2308 |
+ # We store sites in the fundamental domain, so the symmetry element |
|
2309 |
+ # is the same for all onsite terms; it's just the identity. |
|
2310 |
+ identity = ta.array([0] * builder.symmetry.num_directions) |
|
2311 |
+ |
|
2304 | 2312 |
onsite_terms = [ |
2305 | 2313 |
system.Term( |
2306 | 2314 |
subgraph=term_offset + i, |
2315 |
+ symmetry_element=identity, |
|
2307 | 2316 |
hermitian=False, |
2308 | 2317 |
parameters=( |
2309 | 2318 |
params if not isinstance(params, Exception) else None |
... | ... |
@@ -2327,6 +2336,11 @@ def _make_hopping_terms(builder, graph, sites, site_arrays, cell_size, term_offs |
2327 | 2336 |
# Maps hopping edge IDs to the number of the term that the hopping |
2328 | 2337 |
# is a part of. For Hermitian conjugate hoppings "-term_number -1" |
2329 | 2338 |
# is stored instead. |
2339 |
+ # |
|
2340 |
+ # NOTE: 'graph' contains site indices >= cell_size, however 'sites' |
|
2341 |
+ # and 'site_arrays' only contain information about the sites |
|
2342 |
+ # in the fundamental domain. |
|
2343 |
+ sym = builder.symmetry |
|
2330 | 2344 |
|
2331 | 2345 |
site_offsets = np.cumsum([0] + [len(sa) for sa in site_arrays]) |
2332 | 2346 |
|
... | ... |
@@ -2339,11 +2353,27 @@ def _make_hopping_terms(builder, graph, sites, site_arrays, cell_size, term_offs |
2339 | 2353 |
hopping_to_term_nr = collections.OrderedDict() |
2340 | 2354 |
_hopping_term_by_edge_id = [] |
2341 | 2355 |
for tail, head in graph: |
2342 |
- tail_site, head_site = sites[tail], sites[head] |
|
2343 |
- if tail >= cell_size: |
|
2344 |
- # The tail belongs to the previous domain. Find the |
|
2345 |
- # corresponding hopping with the tail in the fund. domain. |
|
2346 |
- tail_site, head_site = builder.symmetry.to_fd(tail_site, head_site) |
|
2356 |
+ # map 'tail' and 'head' so that they are both in the FD, and |
|
2357 |
+ # assign the symmetry element to apply to 'sites[head]' |
|
2358 |
+ # to make the actual hopping. Here we assume that the symmetry |
|
2359 |
+ # may only be NoSymmetry or 1D TranslationalSymmetry. |
|
2360 |
+ if isinstance(sym, NoSymmetry): |
|
2361 |
+ tail_site = sites[tail] |
|
2362 |
+ head_site = sites[head] |
|
2363 |
+ sym_el = ta.array([]) |
|
2364 |
+ else: |
|
2365 |
+ if tail < cell_size and head < cell_size: |
|
2366 |
+ sym_el = ta.array([0]) |
|
2367 |
+ elif head >= cell_size: |
|
2368 |
+ assert tail < cell_size |
|
2369 |
+ head = head - cell_size |
|
2370 |
+ sym_el = ta.array([-1]) |
|
2371 |
+ else: |
|
2372 |
+ tail = tail - cell_size |
|
2373 |
+ sym_el = ta.array([1]) |
|
2374 |
+ tail_site = sites[tail] |
|
2375 |
+ head_site = sym.act(sym_el, sites[head]) |
|
2376 |
+ |
|
2347 | 2377 |
val = builder._get_edge(tail_site, head_site) |
2348 | 2378 |
herm_conj = val is Other |
2349 | 2379 |
if herm_conj: |
... | ... |
@@ -2354,11 +2384,11 @@ def _make_hopping_terms(builder, graph, sites, site_arrays, cell_size, term_offs |
2354 | 2384 |
head_site_array = bisect.bisect(site_offsets, head) - 1 |
2355 | 2385 |
# "key" uniquely identifies a hopping term. |
2356 | 2386 |
if const_val: |
2357 |
- key = (None, tail_site_array, head_site_array) |
|
2387 |
+ key = (None, sym_el, tail_site_array, head_site_array) |
|
2358 | 2388 |
else: |
2359 |
- key = (id(val), tail_site_array, head_site_array) |
|
2389 |
+ key = (id(val), sym_el, tail_site_array, head_site_array) |
|
2360 | 2390 |
if herm_conj: |
2361 |
- key = (key[0], head_site_array, tail_site_array) |
|
2391 |
+ key = (key[0], -sym_el, head_site_array, tail_site_array) |
|
2362 | 2392 |
|
2363 | 2393 |
if key not in hopping_to_term_nr: |
2364 | 2394 |
# start a new term |
... | ... |
@@ -2400,7 +2430,7 @@ def _make_hopping_terms(builder, graph, sites, site_arrays, cell_size, term_offs |
2400 | 2430 |
site_arrays[from_sa].family.norbs, |
2401 | 2431 |
), |
2402 | 2432 |
) |
2403 |
- for (_, to_sa, from_sa), val in |
|
2433 |
+ for (_, _, to_sa, from_sa), val in |
|
2404 | 2434 |
zip(hopping_to_term_nr.keys(), hopping_term_values) |
2405 | 2435 |
] |
2406 | 2436 |
# Sort the hoppings in each term, and also sort the values |
... | ... |
@@ -2411,7 +2441,7 @@ def _make_hopping_terms(builder, graph, sites, site_arrays, cell_size, term_offs |
2411 | 2441 |
zip(hopping_subgraphs, hopping_term_values))) |
2412 | 2442 |
# Store site array index and site offsets rather than sites themselves |
2413 | 2443 |
tmp = [] |
2414 |
- for (_, tail_which, head_which), h in zip(hopping_to_term_nr, |
|
2444 |
+ for (_, _, tail_which, head_which), h in zip(hopping_to_term_nr, |
|
2415 | 2445 |
hopping_subgraphs): |
2416 | 2446 |
start = (site_offsets[tail_which], site_offsets[head_which]) |
2417 | 2447 |
# Transpose to get a pair of arrays rather than array of pairs |
... | ... |
@@ -2429,15 +2459,20 @@ def _make_hopping_terms(builder, graph, sites, site_arrays, cell_size, term_offs |
2429 | 2459 |
err if isinstance(err, Exception) else None |
2430 | 2460 |
for err in hopping_term_parameters |
2431 | 2461 |
] |
2462 |
+ term_symmetry_elements = [ |
|
2463 |
+ sym_el for (_, sym_el, *_) in hopping_to_term_nr.keys() |
|
2464 |
+ ] |
|
2432 | 2465 |
hopping_terms = [ |
2433 | 2466 |
system.Term( |
2434 | 2467 |
subgraph=term_offset + i, |
2468 |
+ symmetry_element=sym_el, |
|
2435 | 2469 |
hermitian=True, # Builders are always Hermitian |
2436 | 2470 |
parameters=( |
2437 | 2471 |
params if not isinstance(params, Exception) else None |
2438 | 2472 |
), |
2439 | 2473 |
) |
2440 |
- for i, params in enumerate(hopping_term_parameters) |
|
2474 |
+ for i, (sym_el, params) in |
|
2475 |
+ enumerate(zip(term_symmetry_elements, hopping_term_parameters)) |
|
2441 | 2476 |
] |
2442 | 2477 |
_hopping_term_by_edge_id = np.array(_hopping_term_by_edge_id) |
2443 | 2478 |
|
... | ... |
@@ -2764,7 +2799,8 @@ class InfiniteVectorizedSystem(_VectorizedFinalizedBuilderMixin, system.Infinite |
2764 | 2799 |
cell_size = len(lsites_with) + len(lsites_without) |
2765 | 2800 |
|
2766 | 2801 |
|
2767 |
- sites = lsites_with + lsites_without + interface |
|
2802 |
+ fd_sites = lsites_with + lsites_without |
|
2803 |
+ sites = fd_sites + interface |
|
2768 | 2804 |
id_by_site = {} |
2769 | 2805 |
for site_id, site in enumerate(sites): |
2770 | 2806 |
id_by_site[site] = site_id |
... | ... |
@@ -2783,24 +2819,23 @@ class InfiniteVectorizedSystem(_VectorizedFinalizedBuilderMixin, system.Infinite |
2783 | 2819 |
del id_by_site # cleanup due to large size |
2784 | 2820 |
|
2785 | 2821 |
# In order to conform to the kwant.system.InfiniteVectorizedSystem |
2786 |
- # interface we need to put the sites that connect to the previous |
|
2787 |
- # cell *first*, then the sites that do not couple to the previous |
|
2788 |
- # cell, then the sites in the previous cell. Because sites in |
|
2789 |
- # a SiteArray are sorted by tag this means that the sites in these |
|
2790 |
- # 3 different sets need to be in different SiteArrays. |
|
2822 |
+ # interface we need to put the interface sites (which have hoppings |
|
2823 |
+ # to the next unit cell) before non-interface sites. |
|
2824 |
+ # Note that we do not *store* the interface sites of the previous |
|
2825 |
+ # unit cell, but we still need to *handle* site indices >= cell_size |
|
2826 |
+ # because those are used e.g. in the graph. |
|
2791 | 2827 |
site_arrays = ( |
2792 | 2828 |
_make_site_arrays(lsites_with) |
2793 | 2829 |
+ _make_site_arrays(lsites_without) |
2794 |
- + _make_site_arrays(interface) |
|
2795 | 2830 |
) |
2796 | 2831 |
|
2797 | 2832 |
(onsite_subgraphs, onsite_terms, onsite_term_values, |
2798 | 2833 |
onsite_term_errors, _onsite_term_by_site_id) =\ |
2799 |
- _make_onsite_terms(builder, sites, site_arrays, term_offset=0) |
|
2834 |
+ _make_onsite_terms(builder, fd_sites, site_arrays, term_offset=0) |
|
2800 | 2835 |
|
2801 | 2836 |
(hopping_subgraphs, hopping_terms, hopping_term_values, |
2802 | 2837 |
hopping_term_errors, _hopping_term_by_edge_id) =\ |
2803 |
- _make_hopping_terms(builder, graph, sites, site_arrays, |
|
2838 |
+ _make_hopping_terms(builder, graph, fd_sites, site_arrays, |
|
2804 | 2839 |
cell_size, term_offset=len(onsite_terms)) |
2805 | 2840 |
|
2806 | 2841 |
# Construct the combined onsite/hopping term datastructures |