Browse code

add (gaussian) current density interpolation and plotting

This method has been prototyped by Adrien Sorgniard with contributions
by Michal Nowak. The prototype has been cleaned-up, debugged, optimized,
and integrated into Kwant by Christoph Groth.

Christoph Groth authored on 18/01/2017 15:03:12 • Joseph Weston committed on 11/05/2017 23:08:33
Showing 4 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,274 @@
1
+# Copyright 2011-2017 Kwant authors.
2
+#
3
+# This file is part of Kwant.  It is subject to the license terms in the file
4
+# LICENSE.rst found in the top-level directory of this distribution and at
5
+# http://kwant-project.org/license.  A list of Kwant authors can be found in
6
+# the file AUTHORS.rst at the top-level directory of this distribution and at
7
+# http://kwant-project.org/authors.
8
+
9
+import numpy as np
10
+from matplotlib.colors import ListedColormap
11
+
12
+
13
+kr_data = [[ 0.98916316, 0.98474381, 0.99210697],
14
+           [ 0.98723538, 0.98138853, 0.98740721],
15
+           [ 0.98524761, 0.97805594, 0.98280815],
16
+           [ 0.98323731, 0.97473672, 0.97825805],
17
+           [ 0.98120432, 0.97143086, 0.97375773],
18
+           [ 0.97914854, 0.96813832, 0.96930811],
19
+           [ 0.97707118, 0.9648587 , 0.96490859],
20
+           [ 0.97496489, 0.96159373, 0.96057068],
21
+           [ 0.97282361, 0.95834495, 0.95630336],
22
+           [ 0.9706266 , 0.95511878, 0.95212518],
23
+           [ 0.96829617, 0.95194965, 0.94800577],
24
+           [ 0.96603689, 0.94881665, 0.94335712],
25
+           [ 0.9642474 , 0.94554816, 0.93828198],
26
+           [ 0.96264371, 0.94222348, 0.93310824],
27
+           [ 0.96112591, 0.93887825, 0.92787613],
28
+           [ 0.9596737 , 0.93552033, 0.92258582],
29
+           [ 0.95826857, 0.93215528, 0.91725354],
30
+           [ 0.95691078, 0.92878338, 0.91187323],
31
+           [ 0.95558706, 0.92540812, 0.90646129],
32
+           [ 0.95429677, 0.92202971, 0.90101648],
33
+           [ 0.95303987, 0.9186481 , 0.89553731],
34
+           [ 0.95180895, 0.91526515, 0.89003356],
35
+           [ 0.95060268, 0.91188113, 0.88450626],
36
+           [ 0.94942096, 0.90849598, 0.87895478],
37
+           [ 0.94826527, 0.9051092 , 0.87337621],
38
+           [ 0.94713012, 0.90172214, 0.86777815],
39
+           [ 0.9460154 , 0.89833471, 0.86216021],
40
+           [ 0.94491934, 0.89494729, 0.85652453],
41
+           [ 0.94384211, 0.89155971, 0.85087045],
42
+           [ 0.94278282, 0.88817211, 0.84519885],
43
+           [ 0.9417403 , 0.88478469, 0.83951108],
44
+           [ 0.94071449, 0.88139736, 0.83380686],
45
+           [ 0.93970482, 0.87801015, 0.8280867 ],
46
+           [ 0.93869093, 0.87463154, 0.82235188],
47
+           [ 0.93767439, 0.87126198, 0.81659016],
48
+           [ 0.93665457, 0.86790165, 0.81080186],
49
+           [ 0.93563073, 0.86455072, 0.80498748],
50
+           [ 0.9346022 , 0.86120939, 0.79914753],
51
+           [ 0.93356835, 0.85787779, 0.7932825 ],
52
+           [ 0.93252858, 0.85455608, 0.78739289],
53
+           [ 0.93148232, 0.8512444 , 0.78147919],
54
+           [ 0.93042904, 0.84794286, 0.77554188],
55
+           [ 0.92936825, 0.84465159, 0.76958144],
56
+           [ 0.92829947, 0.84137068, 0.76359835],
57
+           [ 0.92722226, 0.83810024, 0.75759308],
58
+           [ 0.92613621, 0.83484035, 0.75156611],
59
+           [ 0.92504093, 0.83159108, 0.74551788],
60
+           [ 0.92393607, 0.8283525 , 0.73944885],
61
+           [ 0.92282127, 0.82512468, 0.73335947],
62
+           [ 0.92169623, 0.82190767, 0.72725019],
63
+           [ 0.92056065, 0.81870151, 0.72112144],
64
+           [ 0.91941428, 0.81550625, 0.71497363],
65
+           [ 0.91825684, 0.8123219 , 0.70880719],
66
+           [ 0.91708812, 0.80914851, 0.70262254],
67
+           [ 0.91590788, 0.80598608, 0.69642011],
68
+           [ 0.91471593, 0.80283464, 0.69020029],
69
+           [ 0.91351208, 0.79969419, 0.6839635 ],
70
+           [ 0.91229619, 0.79656474, 0.67771009],
71
+           [ 0.9110681 , 0.79344626, 0.67144042],
72
+           [ 0.9098277 , 0.79033876, 0.66515486],
73
+           [ 0.90857484, 0.78724222, 0.65885379],
74
+           [ 0.90730944, 0.78415662, 0.65253753],
75
+           [ 0.90603137, 0.78108195, 0.64620649],
76
+           [ 0.9047406 , 0.77801816, 0.63986091],
77
+           [ 0.90343706, 0.77496521, 0.63350109],
78
+           [ 0.90212043, 0.77192324, 0.62712707],
79
+           [ 0.9007902 , 0.76889244, 0.62073872],
80
+           [ 0.89944703, 0.76587239, 0.61433695],
81
+           [ 0.8980909 , 0.76286305, 0.60792204],
82
+           [ 0.8967218 , 0.75986435, 0.60149417],
83
+           [ 0.89533975, 0.75687624, 0.59505355],
84
+           [ 0.89394477, 0.75389866, 0.58860036],
85
+           [ 0.89253687, 0.75093154, 0.58213482],
86
+           [ 0.89111598, 0.74797484, 0.57565735],
87
+           [ 0.88968224, 0.74502847, 0.56916787],
88
+           [ 0.88823569, 0.74209235, 0.56266646],
89
+           [ 0.88677639, 0.7391664 , 0.55615322],
90
+           [ 0.88530439, 0.73625056, 0.5496283 ],
91
+           [ 0.88381954, 0.73334485, 0.54309156],
92
+           [ 0.88232071, 0.7304499 , 0.53654178],
93
+           [ 0.88080928, 0.72756485, 0.52998058],
94
+           [ 0.87928542, 0.72468959, 0.52340769],
95
+           [ 0.87774918, 0.72182404, 0.51682313],
96
+           [ 0.87620068, 0.71896812, 0.51022682],
97
+           [ 0.87464002, 0.71612171, 0.50361862],
98
+           [ 0.8730672 , 0.71328477, 0.49699875],
99
+           [ 0.87148244, 0.71045715, 0.49036671],
100
+           [ 0.86988582, 0.70763879, 0.48372234],
101
+           [ 0.86827546, 0.70483075, 0.47706323],
102
+           [ 0.8666533 , 0.70203183, 0.47039155],
103
+           [ 0.86501961, 0.69924189, 0.46370656],
104
+           [ 0.86337451, 0.69646083, 0.45700802],
105
+           [ 0.86171805, 0.69368856, 0.45029569],
106
+           [ 0.86005037, 0.69092498, 0.4435692 ],
107
+           [ 0.8583717 , 0.68816997, 0.43682759],
108
+           [ 0.85668069, 0.68542427, 0.43006904],
109
+           [ 0.85497774, 0.68268759, 0.42329375],
110
+           [ 0.85326416, 0.6799592 , 0.41650135],
111
+           [ 0.85154001, 0.67723901, 0.40969136],
112
+           [ 0.84980535, 0.67452693, 0.40286337],
113
+           [ 0.84806043, 0.67182284, 0.39601592],
114
+           [ 0.84630751, 0.66912636, 0.38913447],
115
+           [ 0.84459103, 0.66641219, 0.38224671],
116
+           [ 0.84291325, 0.66368084, 0.37532092],
117
+           [ 0.84127642, 0.66093085, 0.36835537],
118
+           [ 0.8396827 , 0.65816075, 0.36134959],
119
+           [ 0.83813404, 0.65536906, 0.3543045 ],
120
+           [ 0.83663304, 0.65255404, 0.34721892],
121
+           [ 0.83518227, 0.64971389, 0.34009261],
122
+           [ 0.83378463, 0.64684664, 0.33292467],
123
+           [ 0.83244282, 0.64395026, 0.32571585],
124
+           [ 0.83116067, 0.64102228, 0.31846359],
125
+           [ 0.82994084, 0.63806051, 0.31117051],
126
+           [ 0.82878668, 0.63506246, 0.30383759],
127
+           [ 0.82770268, 0.63202504, 0.29646294],
128
+           [ 0.82669177, 0.62894569, 0.28905098],
129
+           [ 0.8257594 , 0.62581985, 0.28161649],
130
+           [ 0.82491057, 0.62264328, 0.27417247],
131
+           [ 0.82414639, 0.61941489, 0.26670947],
132
+           [ 0.82346948, 0.6161318 , 0.25923681],
133
+           [ 0.82288698, 0.61278636, 0.25181095],
134
+           [ 0.8223949 , 0.6093803 , 0.24442135],
135
+           [ 0.82199347, 0.60591095, 0.23710189],
136
+           [ 0.8216812 , 0.6023757 , 0.22990946],
137
+           [ 0.82144868, 0.59877883, 0.22284964],
138
+           [ 0.82128972, 0.59511966, 0.21600609],
139
+           [ 0.82118758, 0.591407  , 0.20938918],
140
+           [ 0.82112964, 0.58764517, 0.20306727],
141
+           [ 0.8210973 , 0.58384411, 0.19706615],
142
+           [ 0.82107295, 0.58001337, 0.19141507],
143
+           [ 0.82104144, 0.57616127, 0.18614637],
144
+           [ 0.820987  , 0.57229831, 0.18125098],
145
+           [ 0.82089884, 0.56843126, 0.17674506],
146
+           [ 0.82076836, 0.56456672, 0.17261538],
147
+           [ 0.82058591, 0.56071287, 0.16882561],
148
+           [ 0.82035412, 0.55686763, 0.1654141 ],
149
+           [ 0.82006554, 0.55303913, 0.162307  ],
150
+           [ 0.81971999, 0.54922882, 0.15948908],
151
+           [ 0.8193204 , 0.54543542, 0.15696633],
152
+           [ 0.81886751, 0.54166009, 0.15471108],
153
+           [ 0.81836021, 0.53790534, 0.15268999],
154
+           [ 0.81780262, 0.53416961, 0.15088739],
155
+           [ 0.81719522, 0.53045365, 0.14928762],
156
+           [ 0.81654166, 0.52675603, 0.1478763 ],
157
+           [ 0.8158438 , 0.52307639, 0.14663934],
158
+           [ 0.81510297, 0.51941472, 0.14556293],
159
+           [ 0.8143219 , 0.51576993, 0.14463469],
160
+           [ 0.81350256, 0.5121414 , 0.14384267],
161
+           [ 0.81264676, 0.50852856, 0.14317557],
162
+           [ 0.81175539, 0.50493143, 0.14262199],
163
+           [ 0.81083033, 0.50134931, 0.14217199],
164
+           [ 0.80987366, 0.49778124, 0.14181673],
165
+           [ 0.80888697, 0.49422657, 0.14154764],
166
+           [ 0.80787088, 0.49068512, 0.14136263],
167
+           [ 0.80682868, 0.48715438, 0.1412702 ],
168
+           [ 0.80576011, 0.48363561, 0.14124257],
169
+           [ 0.80466553, 0.48012899, 0.14127189],
170
+           [ 0.80355703, 0.47662617, 0.14134325],
171
+           [ 0.80244307, 0.47312268, 0.14140455],
172
+           [ 0.80132288, 0.46961902, 0.14145468],
173
+           [ 0.80019799, 0.46611382, 0.14149602],
174
+           [ 0.7990684 , 0.46260695, 0.14152863],
175
+           [ 0.79793402, 0.45909833, 0.14155245],
176
+           [ 0.79679443, 0.45558816, 0.14156689],
177
+           [ 0.79564905, 0.45207679, 0.14157115],
178
+           [ 0.79449895, 0.44856316, 0.1415669 ],
179
+           [ 0.79334425, 0.44504703, 0.1415543 ],
180
+           [ 0.7921849 , 0.44152826, 0.14153333],
181
+           [ 0.791021  , 0.43800659, 0.14150417],
182
+           [ 0.7898508 , 0.43448337, 0.14146434],
183
+           [ 0.78867629, 0.4309567 , 0.14141669],
184
+           [ 0.78749716, 0.42742668, 0.14136083],
185
+           [ 0.7863135 , 0.42389299, 0.14129692],
186
+           [ 0.78512536, 0.42035543, 0.14122502],
187
+           [ 0.7839324 , 0.41681408, 0.14114469],
188
+           [ 0.78273406, 0.41326924, 0.14105512],
189
+           [ 0.78153119, 0.40971994, 0.14095756],
190
+           [ 0.78032382, 0.4061659 , 0.14085208],
191
+           [ 0.77911231, 0.40260657, 0.14073912],
192
+           [ 0.77789631, 0.399042  , 0.14061828],
193
+           [ 0.77667586, 0.39547192, 0.1404896 ],
194
+           [ 0.77545064, 0.39189639, 0.14035261],
195
+           [ 0.77422054, 0.38831521, 0.14020724],
196
+           [ 0.77298612, 0.38472759, 0.14005425],
197
+           [ 0.77174749, 0.38113312, 0.13989379],
198
+           [ 0.77050465, 0.37753149, 0.13972588],
199
+           [ 0.76925755, 0.37392242, 0.13955047],
200
+           [ 0.76800622, 0.37030556, 0.13936762],
201
+           [ 0.76675073, 0.36668048, 0.13917742],
202
+           [ 0.76549072, 0.36304722, 0.13897942],
203
+           [ 0.76422604, 0.35940553, 0.13877348],
204
+           [ 0.76295723, 0.35575449, 0.13856031],
205
+           [ 0.7616843 , 0.35209368, 0.13833995],
206
+           [ 0.76040723, 0.34842269, 0.13811243],
207
+           [ 0.75912615, 0.34474093, 0.1378779 ],
208
+           [ 0.75784098, 0.34104803, 0.13763632],
209
+           [ 0.75655175, 0.33734346, 0.13738776],
210
+           [ 0.75525845, 0.33362676, 0.13713223],
211
+           [ 0.75396105, 0.32989738, 0.13686976],
212
+           [ 0.75265958, 0.32615477, 0.13660042],
213
+           [ 0.75135404, 0.32239833, 0.13632426],
214
+           [ 0.75004443, 0.31862745, 0.13604133],
215
+           [ 0.74873043, 0.31484189, 0.13575126],
216
+           [ 0.7474124 , 0.31104052, 0.1354546 ],
217
+           [ 0.74609036, 0.30722265, 0.1351514 ],
218
+           [ 0.74476429, 0.30338754, 0.13484171],
219
+           [ 0.7434342 , 0.2995344 , 0.13452559],
220
+           [ 0.74210012, 0.29566234, 0.13420317],
221
+           [ 0.740762  , 0.29177058, 0.13387443],
222
+           [ 0.73941986, 0.28785816, 0.13353947],
223
+           [ 0.73807366, 0.28392417, 0.13319832],
224
+           [ 0.73672338, 0.27996758, 0.13285105],
225
+           [ 0.73536902, 0.27598733, 0.13249773],
226
+           [ 0.73401057, 0.27198225, 0.13213842],
227
+           [ 0.73264812, 0.267951  , 0.13177331],
228
+           [ 0.7312816 , 0.26389237, 0.13140239],
229
+           [ 0.72991091, 0.25980509, 0.13102567],
230
+           [ 0.72853607, 0.25568766, 0.13064324],
231
+           [ 0.72715709, 0.25153846, 0.13025522],
232
+           [ 0.72577404, 0.24735572, 0.12986175],
233
+           [ 0.72438675, 0.24313784, 0.12946276],
234
+           [ 0.72299506, 0.23888311, 0.12905819],
235
+           [ 0.72159891, 0.23458955, 0.12864803],
236
+           [ 0.72019841, 0.23025473, 0.12823254],
237
+           [ 0.71879351, 0.22587627, 0.12781177],
238
+           [ 0.71738445, 0.22145117, 0.12738605],
239
+           [ 0.71597106, 0.2169768 , 0.12695531],
240
+           [ 0.71455619, 0.21244509, 0.12652294],
241
+           [ 0.71313673, 0.20785768, 0.12608696],
242
+           [ 0.71171317, 0.20320993, 0.12564796],
243
+           [ 0.71028524, 0.19849817, 0.12520579],
244
+           [ 0.70885023, 0.19372288, 0.12475808],
245
+           [ 0.70741049, 0.18887484, 0.12430712],
246
+           [ 0.70596683, 0.18394695, 0.12385374],
247
+           [ 0.70451965, 0.17893205, 0.12339841],
248
+           [ 0.70306509, 0.17383098, 0.12293779],
249
+           [ 0.70160541, 0.16863153, 0.12247404],
250
+           [ 0.70014347, 0.16331865, 0.12200979],
251
+           [ 0.69867317, 0.15789552, 0.12153977],
252
+           [ 0.69719976, 0.15233907, 0.12106873],
253
+           [ 0.69571992, 0.14664349, 0.12059389],
254
+           [ 0.69423655, 0.14078634, 0.12011789],
255
+           [ 0.69274566, 0.13475932, 0.11963739],
256
+           [ 0.69125189, 0.12852876, 0.11915653],
257
+           [ 0.68975221, 0.12207639, 0.1186728 ],
258
+           [ 0.68824567, 0.11537334, 0.11818552],
259
+           [ 0.6867347 , 0.10837306, 0.11769691],
260
+           [ 0.68521904, 0.10102592, 0.11720685],
261
+           [ 0.68369886, 0.09326599, 0.11671559],
262
+           [ 0.68217313, 0.08501006, 0.11622239],
263
+           [ 0.68064138, 0.07614058, 0.11572698],
264
+           [ 0.67910607, 0.06647368, 0.11523153],
265
+           [ 0.67756743, 0.05573816, 0.11473634],
266
+           [ 0.67602649, 0.04347155, 0.11424238],
267
+           [ 0.67448806, 0.02955075, 0.11375372],
268
+           [ 0.67299504, 0.0153711 , 0.1133058 ]]
269
+
270
+# Rescale colormap to start from white.
271
+kr_data = np.array(kr_data)
272
+kr_data = np.clip(kr_data / kr_data[0], 0, 1)
273
+
274
+kwant_red = ListedColormap(kr_data, name="kwant red")
... ...
@@ -20,6 +20,7 @@ import functools
20 20
 import warnings
21 21
 import cmath
22 22
 import numpy as np
23
+import scipy
23 24
 import tinyarray as ta
24 25
 from scipy import spatial, interpolate
25 26
 from math import cos, sin, pi, sqrt
... ...
@@ -32,7 +33,9 @@ try:
32 33
     import matplotlib
33 34
     from matplotlib.figure import Figure
34 35
     from matplotlib import collections
36
+    from matplotlib import colors
35 37
     from matplotlib.backends.backend_agg import FigureCanvasAgg
38
+    from . import _colormaps
36 39
     mpl_enabled = True
37 40
     try:
38 41
         from mpl_toolkits import mplot3d
... ...
@@ -1581,6 +1584,9 @@ def map(sys, value, colorbar=True, cmap=None, vmin=None, vmax=None, a=None,
1581 1584
     else:
1582 1585
         fig = None
1583 1586
 
1587
+    if cmap is None:
1588
+        cmap = _colormaps.kwant_red
1589
+
1584 1590
     # Note that we tell imshow to show the array created by mask_interpolate
1585 1591
     # faithfully and not to interpolate by itself another time.
1586 1592
     image = ax.imshow(img.T, extent=(min[0], max[0], min[1], max[1]),
... ...
@@ -1794,6 +1800,233 @@ def spectrum(syst, x, y=None, params=None, mask=None, file=None,
1794 1800
         return output_fig(fig, file=file, show=show)
1795 1801
 
1796 1802
 
1803
+def interpolate_current(syst, current, sigma=1, gauss_range=2, n=3, a=None):
1804
+    """Interpolate currents in a system onto a regular grid.
1805
+
1806
+    The system graph together with current intensities defines a "discrete"
1807
+    current density field where the current density is non-zero only on the
1808
+    straight lines that connect sites that are coupled by a hopping term.
1809
+
1810
+    To make this vector field easier to visualize and interpret at different
1811
+    length scales, it is smoothed by convoluting it with a kernel function
1812
+    that has a (Gaussian) pulse-like shape.
1813
+
1814
+    This function samples the smoothed field on a regular (square or cubic)
1815
+    grid.
1816
+
1817
+    Parameters
1818
+    ----------
1819
+    syst : A finalized system
1820
+        The system on which we are going to calculate the field.
1821
+    current : '1D array of float'
1822
+        Must contain the intensity on each hoppings in the same order that they
1823
+        appear in syst.graph.
1824
+    sigma : 'float'
1825
+        Parameter of the Gaussian used to generate the field :
1826
+        exp(-x**2/(2*sigma**2)), the unit of sigma is a.
1827
+    gauss_range : int
1828
+        Number of sigma after which we consider the Gaussian equal to 0.
1829
+    n : int
1830
+        Number of point the grid must have per sigma.
1831
+    a : float
1832
+        By default, the length of the shortest hoppings.
1833
+
1834
+    Returns
1835
+    -------
1836
+    region : list of the coordonates of the grid for each dimension
1837
+    field : value of the generated field on the grid points
1838
+    """
1839
+    if not isinstance(syst, builder.FiniteSystem):
1840
+        raise TypeError("The system needs to be finalized.")
1841
+
1842
+    if len(current) != syst.graph.num_edges:
1843
+        raise ValueError("Current and hoppings arrays do not have the same"
1844
+                         " length.")
1845
+
1846
+    # hops: hoppings (pairs of points)
1847
+    dim = len(syst.sites[0].pos)
1848
+    hops = np.empty((syst.graph.num_edges, 2, dim))
1849
+    for k, (i, j) in enumerate(syst.graph):
1850
+        # +ve direction defined as *from* j *to* i
1851
+        hops[k][0] = syst.sites[j].pos
1852
+        hops[k][1] = syst.sites[i].pos
1853
+
1854
+    # lens: scaled lengths of hoppings
1855
+    # dirs: normalized directions of hoppings
1856
+    dirs = hops[:, 1] - hops[:, 0]
1857
+    lens = np.sqrt(np.sum(dirs * dirs, -1))
1858
+    dirs /= lens[:, None]
1859
+    if a == None:
1860
+        a = min(lens)
1861
+    sigma *= a
1862
+    r = sigma * gauss_range
1863
+    factor = 0.5 * pow(sigma * sqrt(2*pi), 1 - dim)
1864
+    scale = 1 / (sigma * sqrt(2))
1865
+    lens *= scale
1866
+
1867
+    # Create field array.
1868
+    field_shape = np.zeros(dim + 1, int)
1869
+    field_shape[dim] = dim
1870
+    min_hops = np.min(hops, 1)
1871
+    max_hops = np.max(hops, 1)
1872
+    bbox_min = np.min(min_hops, 0)
1873
+    bbox_max = np.max(max_hops, 0)
1874
+    for d in range(dim):
1875
+        field_shape[d] = int((bbox_max[d] - bbox_min[d])*n / sigma + 2*gauss_range*n)
1876
+        if field_shape[d] % 2:
1877
+            field_shape[d] += 1
1878
+    field = np.zeros(field_shape)
1879
+
1880
+    region = [np.linspace(bbox_min[d] - gauss_range*sigma, bbox_max[d] + gauss_range*sigma,
1881
+                          field_shape[d])
1882
+              for d in range(dim)]
1883
+
1884
+    grid_density = (field_shape[:dim] - 1) / (bbox_max + 2*r - bbox_min)
1885
+    slices = np.empty((len(hops), dim, 2), int)
1886
+    slices[:, :, 0] = np.floor((min_hops - bbox_min) * grid_density)
1887
+    slices[:, :, 1] = np.ceil((max_hops + 2*r - bbox_min) * grid_density)
1888
+
1889
+    # Interpolate the field for each hopping.
1890
+    erf = scipy.special.erf
1891
+    for i in range(len(hops)):
1892
+        if not np.diff(slices[i]).all():
1893
+            # Zero volume: nothing to do.
1894
+            continue
1895
+
1896
+        field_slice = [slice(*slices[i, d]) for d in range(dim)]
1897
+
1898
+        # Coordinates of the grid points that are within range of the current
1899
+        # hopping.
1900
+        coords = np.meshgrid(*[region[d][field_slice[d]] for d in range(dim)],
1901
+                             sparse=True, indexing='ij')
1902
+        coords -= hops[i, 0]
1903
+
1904
+        # Convert "coords" into scaled cylindrical coordinates with regard to
1905
+        # the hopping.
1906
+        z = np.dot(coords, dirs[i])
1907
+        rho = np.sqrt(np.abs(np.sum(coords * coords) - z*z))
1908
+        z *= scale
1909
+        rho *= scale
1910
+
1911
+        magns = current[i] * factor * np.exp(-rho * rho)
1912
+        magns *= erf(z) - erf(z - lens[i])
1913
+
1914
+        field[field_slice] += dirs[i] * magns[..., None]
1915
+
1916
+    # 'field' contains contributions from both hoppings (i, j) and (j, i)
1917
+    return region, field / 2
1918
+
1919
+
1920
+def current(syst, current, sigma=1, gauss_range=6, n=3, a=None,
1921
+            colorbar=True, cmap=None, file=None, show=True, dpi=None,
1922
+            fig_size=None, ax=None):
1923
+    """Show interpolated map of a function defined for the hoppings of a system.
1924
+
1925
+    The system graph together with current intensities defines a "discrete"
1926
+    current density field where the current density is non-zero only on the
1927
+    straight lines that connect sites that are coupled by a hopping term.
1928
+
1929
+    To make this vector field easier to visualize and interpret at different
1930
+    length scales, it is smoothed by convoluting it with a kernel function
1931
+    that has a (Gaussian) pulse-like shape.
1932
+
1933
+    This function samples the smoothed field on a regular (square or cubic)
1934
+    grid.
1935
+
1936
+    Parameters
1937
+    ----------
1938
+    syst : `kwant.system.FiniteSystem`
1939
+        The system for which to plot the ``current``.
1940
+    current : sequence of float
1941
+        Sequence of values defining currents on each hopping of the system.
1942
+        Ordered in the same way as ``syst.graph``. This typically will be
1943
+        the result of evaluating a `~kwant.operator.Current` operator.
1944
+    sigma : 'float'
1945
+        Parameter of the Gaussian used to generate the field:
1946
+        exp(-x**2/(2*sigma**2)), the unit of sigma is ``a``.
1947
+    gauss_range : int
1948
+        Number of sigma after which we consider the Gaussian equal to 0.
1949
+    n : int
1950
+        Number of points the grid must have per sigma.
1951
+    a : float
1952
+        By default, the length of the shortest hoppings.
1953
+    colorbar : bool, optional
1954
+        Whether to show a color bar if numerical data has to be plotted.
1955
+        Defaults to `True`. If `ax` is provided, the colorbar is never plotted.
1956
+    cmap : ``matplotlib`` color map or `None`
1957
+        The color map used for sites and optionally hoppings, if `None`,
1958
+        ``matplotlib`` default is used.
1959
+    file : string or file object or `None`
1960
+        The output file.  If `None`, output will be shown instead.
1961
+    show : bool
1962
+        Whether ``matplotlib.pyplot.show()`` is to be called, and the output is
1963
+        to be shown immediately.  Defaults to `True`.
1964
+    dpi : float or `None`
1965
+        Number of pixels per inch.  If not set the ``matplotlib`` default is
1966
+        used.
1967
+    fig_size : tuple or `None`
1968
+        Figure size `(width, height)` in inches.  If not set, the default
1969
+        ``matplotlib`` value is used.
1970
+    ax : ``matplotlib.axes.Axes`` instance or `None`
1971
+        If `ax` is not `None`, no new figure is created, but the plot is done
1972
+        within the existing Axes `ax`. in this case, `file`, `show`, `dpi`
1973
+        and `fig_size` are ignored.
1974
+
1975
+    Returns
1976
+    -------
1977
+    fig : matplotlib figure
1978
+        A figure with the output if `ax` is not set, else None.
1979
+    """
1980
+
1981
+    if not mpl_enabled:
1982
+        raise RuntimeError("matplotlib was not found, but is required "
1983
+                           "for current()")
1984
+
1985
+    region, field = interpolate_current(syst, current, sigma=sigma,
1986
+                                        gauss_range=gauss_range, n=n, a=a)
1987
+
1988
+    if len(region) != 2:
1989
+        raise ValueError("Only 2D field can be plotted.")
1990
+
1991
+    # The default colormap is extremely ugly with streamplot.
1992
+    if cmap is None:
1993
+        cmap = _colormaps.kwant_red
1994
+
1995
+    if ax is None:
1996
+        fig = Figure()
1997
+        if dpi is not None:
1998
+            fig.set_dpi(dpi)
1999
+        if fig_size is not None:
2000
+            fig.set_figwidth(fig_size[0])
2001
+            fig.set_figheight(fig_size[1])
2002
+        ax = fig.add_subplot(1, 1, 1, aspect='equal')
2003
+    else:
2004
+        fig = None
2005
+
2006
+    Y, X = np.ogrid[region[0][0] : region[0][-1] : 1j * len(region[0]),
2007
+                    region[1][0] : region[1][-1] : 1j * len(region[1])]
2008
+
2009
+    field = field.transpose(1, 0, 2)  # reverse X and Y axes
2010
+    speed = np.linalg.norm(field, axis=-1)
2011
+    image = ax.imshow(speed[::-1], cmap=cmap,
2012
+                      interpolation='bicubic',
2013
+                      extent=(region[0][0], region[0][-1],
2014
+                              region[1][0], region[1][-1]))
2015
+    linewidth = 2 * (speed / (np.max(speed) or 1))
2016
+    ax.streamplot(Y.T, X.T, field[:,:,0], field[:,:,1],
2017
+                  linewidth=linewidth, cmap=cmap, color=speed,
2018
+                  norm=colors.Normalize(vmin=0, vmax=np.max(speed) * 1.5))
2019
+
2020
+    ax.set_xlim(region[0][0], region[0][-1])
2021
+    ax.set_ylim(region[1][0], region[1][-1])
2022
+
2023
+    if colorbar and fig is not None:
2024
+        fig.colorbar(image)
2025
+
2026
+    if fig is not None:
2027
+        return output_fig(fig, file=file, show=show)
2028
+
2029
+
1797 2030
 # TODO (Anton): Fix plotting of parts of the system using color = np.nan.
1798 2031
 # Not plotting sites currently works, not plotting hoppings does not.
1799 2032
 # TODO (Anton): Allow a more flexible treatment of position than pos_transform
... ...
@@ -8,10 +8,16 @@
8 8
 
9 9
 import tempfile
10 10
 import warnings
11
+import itertools
11 12
 import numpy as np
13
+import tinyarray as ta
14
+from math import cos, sin, pi
15
+import scipy.integrate
16
+import pytest
17
+
12 18
 import kwant
13 19
 from kwant import plotter
14
-import pytest
20
+from kwant._common import ensure_rng
15 21
 
16 22
 if plotter.mpl_enabled:
17 23
     from mpl_toolkits import mplot3d
... ...
@@ -40,7 +46,7 @@ def test_importable_without_matplotlib():
40 46
 def syst_2d(W=3, r1=3, r2=8):
41 47
     a = 1
42 48
     t = 1.0
43
-    lat = kwant.lattice.square(a)
49
+    lat = kwant.lattice.square(a, norbs=1)
44 50
     syst = kwant.Builder()
45 51
 
46 52
     def ring(pos):
... ...
@@ -237,3 +243,176 @@ def test_spectrum():
237 243
     with tempfile.TemporaryFile('w+b') as out:
238 244
         plotter.spectrum(ham, ('a', vals), ('b', 2 * vals), params=dict(c=1),
239 245
                          mask=mask, file=out)
246
+
247
+
248
+def syst_rect(lat, salt, W=3, L=50):
249
+    syst = kwant.Builder()
250
+
251
+    ll = L//2
252
+    ww = W//2
253
+
254
+    def onsite(site):
255
+        return 4 + 0.1 * kwant.digest.gauss(site.tag, salt=salt)
256
+
257
+    syst[(lat(i, j) for i in range(-ll, ll+1)
258
+         for j in range(-ww, ww+1))] = onsite
259
+    syst[lat.neighbors()] = -1
260
+
261
+    sym = kwant.TranslationalSymmetry(lat.vec((-1, 0)))
262
+    lead = kwant.Builder(sym)
263
+    lead[(lat(0, j) for j in range(-ww, ww + 1))] = 4
264
+    lead[lat.neighbors()] = -1
265
+
266
+    syst.attach_lead(lead)
267
+    syst.attach_lead(lead.reversed())
268
+
269
+    return syst
270
+
271
+
272
+def div(F):
273
+    """Calculate the divergence of a vector field F."""
274
+    assert len(F.shape[:-1]) == F.shape[-1]
275
+    return sum(np.gradient(F[..., i])[i] for i in range(F.shape[-1]))
276
+
277
+
278
+def rotational_currents(g):
279
+    """Return a basis of divergence-free currents for a closed graph.
280
+
281
+    Given the graph 'g' of a Kwant system, returns a sequence of arrays
282
+    which are linearly independent, divergence-free currents on the graph.
283
+    """
284
+    #'A' represents the set of expressions that give the net current flow
285
+    # into the system sites. 'perm' is a map from the edges of a graph
286
+    # with only 1 edge per hopping to the proper Kwant graph (2 edges
287
+    # per hopping).
288
+    A = np.zeros((g.num_nodes, g.num_edges // 2))
289
+    hoppings = dict()
290
+    perm_data = np.zeros(g.num_edges)
291
+    perm_ij = np.zeros((2, g.num_edges))
292
+    i = 0
293
+    for k, (a, b) in enumerate(g):
294
+        hop = frozenset((a, b))
295
+        if hop not in hoppings:
296
+            A[a, i] = 1
297
+            A[b, i] = -1
298
+            hoppings[hop] = i
299
+            perm_data[k] = 1
300
+            perm_ij[:, k] = (k, i)
301
+            i += 1
302
+        else:
303
+            perm_data[k] = -1
304
+            perm_ij[:, k] = (k, hoppings[hop])
305
+
306
+    perm = scipy.sparse.coo_matrix((perm_data, perm_ij))
307
+
308
+    # Get the row vectors of V with singular value 0. These form
309
+    # a basis for the right null space of 'A'.
310
+    U, S, V = np.linalg.svd(A)
311
+    tol = S.max() * max(A.shape) * np.finfo(S.dtype).eps
312
+    rank = sum(S > tol)
313
+    # Transform null space basis into vectors defined over the full
314
+    # hopping space (both hopping directions).
315
+    null_space_basis = V[-(len(V) - rank):].transpose()
316
+    null_space_basis = perm.dot(null_space_basis).transpose()
317
+    return null_space_basis
318
+
319
+
320
+def test_current_interpolation():
321
+
322
+    ## Passing a Builder will raise an error
323
+    pytest.raises(TypeError, plotter.interpolate_current, syst_2d(), None)
324
+
325
+    def R(theta):
326
+        return ta.array([[cos(theta), -sin(theta)], [sin(theta), cos(theta)]])
327
+
328
+    def make_lattice(a, theta):
329
+        x = ta.dot(R(theta), (a, 0))
330
+        y = ta.dot(R(theta), (0, a))
331
+        return kwant.lattice.general([x, y], norbs=1)
332
+
333
+    angles = (0, pi/6, pi/4)
334
+    lat_constants = (1, 2)
335
+
336
+    ## Check current through cross section is same for different lattice
337
+    ## parameters and orientations of the system wrt. the discretization grid
338
+    for a, theta in itertools.product(lat_constants, angles):
339
+        lat = make_lattice(a, theta)
340
+        syst = syst_rect(lat, salt='0').finalized()
341
+        psi = kwant.wave_function(syst, energy=3)(0)
342
+
343
+        def cut(a, b):
344
+            return b.tag[0] < 0 and a.tag[0] >= 0
345
+
346
+        J = kwant.operator.Current(syst).bind()
347
+        J_cut = kwant.operator.Current(syst, where=cut, sum=True).bind()
348
+        (x, y), j0 = plotter.interpolate_current(syst, J(psi[0]), gauss_range=5)
349
+
350
+        # slice field perpendicular to a cut along the y axis
351
+        y_axis = (np.argmin(np.abs(x)), slice(None), 0)
352
+        ## Integrate and compare with summed current.
353
+        assert np.isclose(J_cut(psi[0]),
354
+                          scipy.integrate.simps(j0[y_axis], y))
355
+
356
+    ## Check that taking a finer grid or changing the broadening does not
357
+    ## affect the total integrated current.
358
+    n_s = (3, 5)
359
+    sigma_s = (1, 0.5)
360
+
361
+    for n, sigma in zip(n_s, sigma_s):
362
+        (x, y), j0 = plotter.interpolate_current(syst, J(psi[0]), n=n,
363
+                                                 sigma=sigma, gauss_range=5)
364
+        # slice field perpendicular to a cut along the y axis
365
+        y_axis = (np.argmin(np.abs(x)), slice(None), 0)
366
+        assert np.isclose(J_cut(psi[0]),
367
+                          scipy.integrate.simps(j0[y_axis], y))
368
+
369
+    ### Tests on a divergence-free current (closed system)
370
+
371
+    lat = kwant.lattice.general([(1, 0), (0.5, np.sqrt(3) / 2)])
372
+    syst = kwant.Builder()
373
+    sites = [lat(0, 0), lat(1, 0), lat(0, 1), lat(2, 2)]
374
+    syst[sites] = None
375
+    syst[((s, t) for s, t in itertools.product(sites, sites) if s != t)] = None
376
+    del syst[lat(0, 0), lat(2, 2)]
377
+    syst = syst.finalized()
378
+
379
+    # generate random divergence-free currents
380
+    Js = rotational_currents(syst.graph)
381
+    rng = ensure_rng(3)
382
+    J0 = sum(rng.rand(len(Js))[:, None] * Js)
383
+    J1 = sum(rng.rand(len(Js))[:, None] * Js)
384
+
385
+    # Sanity check that diverence on the graph is 0
386
+    divergence = np.zeros(len(syst.sites))
387
+    for (a, _), current in zip(syst.graph, J0):
388
+        divergence[a] += current
389
+    assert np.allclose(divergence, 0)
390
+
391
+    _, j0 = plotter.interpolate_current(syst, J0)
392
+    _, j1 = plotter.interpolate_current(syst, J1)
393
+
394
+    ## Test linearity of interpolation.
395
+    _, j_tot = plotter.interpolate_current(syst, J0 + 2 * J1)
396
+    assert np.allclose(j_tot, j0 + 2 * j1)
397
+
398
+    ## Test that divergence of interpolated current is approximately zero.
399
+    # For currents not aligned with the interpolation grid this is only
400
+    # 1/a**2 accurate.
401
+    _, j = plotter.interpolate_current(syst, J0, n=20, gauss_range=4)
402
+    div_j = np.max(np.abs(div(j)))
403
+    assert np.isclose(div_j, 0, atol=1E-4)
404
+
405
+
406
+@pytest.mark.skipif(not plotter.mpl_enabled, reason="No matplotlib available.")
407
+def test_current():
408
+    syst = syst_2d().finalized()
409
+    J = kwant.operator.Current(syst)
410
+    current = J(kwant.wave_function(syst, energy=1)(1)[0])
411
+
412
+    # Test good codepath
413
+    with tempfile.TemporaryFile('w+b') as out:
414
+        plotter.current(syst, current, file=out)
415
+
416
+        fig = pyplot.Figure()
417
+        ax = fig.add_subplot(1, 1, 1)
418
+        plotter.current(syst, current, ax=ax, file=out)
240 419
new file mode 100644
... ...
@@ -0,0 +1,38 @@
1
+{
2
+    "license": "http://creativecommons.org/publicdomain/zero/1.0/",
3
+    "usage-hints": [
4
+        "red-green-colorblind-safe",
5
+        "greyscale-safe",
6
+        "sequential"
7
+    ],
8
+    "colors": "fcfbfdfcfafcfbf9fbfbf9f9faf8f8faf7f7f9f6f6f9f5f5f8f4f4f8f4f3f7f3f2f6f2f1f6f1eff5f0eef5efedf5efebf4eeeaf4ede9f4ece7f3ebe6f3eae4f3e9e3f2e9e2f2e8e0f2e7dff2e6ddf1e5dcf1e4daf1e3d9f0e2d8f0e2d6f0e1d5f0e0d3efdfd2efded0efddcfefdccdeedccceedbcaeedac9eed9c7edd8c6edd7c4edd7c3ecd6c1ecd5c0ecd4beecd3bdebd2bbebd2b9ebd1b8ead0b6eacfb5eaceb3eaceb2e9cdb0e9ccaee9cbade8caabe8caaae8c9a8e7c8a6e7c7a5e7c6a3e6c6a2e6c5a0e6c49ee5c39de5c39be5c299e4c198e4c096e4bf94e3bf93e3be91e3bd8fe2bc8ee2bc8ce1bb8ae1ba89e1ba87e0b985e0b884dfb782dfb780dfb67fdeb57ddeb47bddb47addb378ddb276dcb275dcb173dbb071dbaf6fdaaf6edaae6cdaad6ad9ad68d9ac67d8ab65d8ab63d7aa61d7a960d7a95ed6a85cd6a75ad5a659d5a657d5a555d4a453d4a351d4a34fd3a24dd3a14cd3a04ad3a048d29f46d29e44d29d42d29c40d29b3ed29b3cd29a3bd19939d19837d19735d19634d19532d19431d1932fd1922ed1912dd1902cd18f2bd18e2ad18d29d18c29d18b28d18a27d18927d18826d08726d08626d08525d08425d08425cf8325cf8225cf8124cf8024cf7f24ce7e24ce7d24ce7c24cd7b24cd7a24cd7a24cd7924cc7824cc7724cc7624cb7524cb7424cb7324cb7224ca7124ca7124ca7024c96f24c96e24c96d24c96c24c86b24c86a24c86924c76824c76824c76724c66624c66524c66424c56324c56224c56124c46024c45f24c45e24c45e23c35d23c35c23c35b23c25a23c25923c25823c15723c15623c15523c05423c05323c05223bf5123bf5023bf4f23be4e22be4d22be4c22bd4b22bd4a22bd4922bc4822bc4722bc4622bb4522bb4422ba4322ba4221ba4121b94021b93f21b93e21b83d21b83c21b83b21b73a21b73820b73720b63620b63520b53420b53320b53120b43020b42f20b42e1fb32c1fb32b1fb32a1fb2281fb2271fb1251fb1241fb1221fb0211eb01f1eb01d1eaf1c1eaf1a1eae181eae161eae131ead111dad0e1dac0b1dac081dac041d",
9
+    "colorspace": "sRGB",
10
+    "name": "kwant red",
11
+    "extensions": {
12
+        "https://matplotlib.org/viscm": {
13
+            "yp": [
14
+                -2.0153712378334347,
15
+                10.887492636952686,
16
+                28.27830916383833,
17
+                20.84513758379849,
18
+                15.655942329808425
19
+            ],
20
+            "max_Jp": 41,
21
+            "cmtype": "linear",
22
+            "uniform_colorspace": "CAM02-UCS",
23
+            "spline_method": "CatmulClark",
24
+            "fixed": -1,
25
+            "filter_k": 100,
26
+            "min_Jp": 99,
27
+            "xp": [
28
+                -1.2674960029171558,
29
+                5.464432975232114,
30
+                4.482693332585356,
31
+                21.45276429833666,
32
+                33.65438557123224
33
+            ]
34
+        }
35
+    },
36
+    "domain": "continuous",
37
+    "content-type": "application/vnd.matplotlib.colormap-v1+json"
38
+}