Browse code

update vectorized finalized Builders to use new storage format

+ 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.

Joseph Weston authored on 04/12/2019 17:02:39
Showing 1 changed files
... ...
@@ -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