spin_potential_shape.rst 23 KB
Newer Older
1
2
3
4
5
More interesting systems: spin, potential, shape
------------------------------------------------

Each of the following three examples highlights different ways to go beyond the
very simple examples of the previous section.
6
7
8
9
10
11

.. _tutorial_spinorbit:

Matrix structure of on-site and hopping elements
................................................

12
13
14
15
16
17
.. seealso::
    You can execute the code examples live in your browser by
    activating thebelab:

    .. thebe-button:: Activate Thebelab

18
19
.. seealso::
    The complete source code of this example can be found in
20
21
22
23
    :jupyter-download:script:`spin_orbit`

.. jupyter-kernel::
    :id: spin_orbit
24

25
26
We begin by extending the simple 2DEG-Hamiltonian by a Rashba spin-orbit
coupling and a Zeeman splitting due to an external magnetic field:
27
28
29

.. math::

30
    H = \frac{-\hbar^2}{2 m} (\partial_x^2+\partial_y^2) -
31
32
33
34
35
36
37
38
      i \alpha (\partial_x \sigma_y - \partial_y \sigma_x) +
      E_\text{Z} \sigma_z +  V(y)

Here :math:`\sigma_{x,y,z}` denote the Pauli matrices.

It turns out that this well studied Rashba-Hamiltonian has some peculiar
properties in (ballistic) nanowires: It was first predicted theoretically
in `Phys. Rev. Lett. 90, 256601 (2003)
39
<https://doi.org/10.1103/PhysRevLett.90.256601>`_ that such a system should
40
41
42
exhibit non-monotonic conductance steps due to a spin-orbit gap. Only
very recently, this non-monotonic behavior has been supposedly
observed in experiment: `Nature Physics 6, 336 (2010)
43
<https://doi.org/10.1038/nphys1626>`_. Here
44
45
46
47
we will show that a very simple extension of our previous examples will
exactly show this behavior (Note though that no care was taken to choose
realistic parameters).

48
49
The tight-binding model corresponding to the Rashba-Hamiltonian naturally
exhibits a 2x2-matrix structure of onsite energies and hoppings.  In order to
50
use matrices in our program, we import the Tinyarray package.  (`NumPy
51
<https://numpy.org/>`_ would work as well, but Tinyarray is much faster
52
for small arrays.)
53

54
55
56
57
58
59
60
61
62
63
.. jupyter-execute::
    :hide-code:

    # Tutorial 2.3.1. Matrix structure of on-site and hopping elements
    # ================================================================
    #
    # Physics background
    # ------------------
    #  Gaps in quantum wires with spin-orbit coupling and Zeeman splititng,
    #  as theoretically predicted in
64
    #   https://doi.org/10.1103/PhysRevLett.90.256601
65
    #  and (supposedly) experimentally oberved in
66
    #   https://doi.org/10.1038/nphys1626
67
68
69
70
71
72
73
74
75
76
    #
    # Kwant features highlighted
    # --------------------------
    #  - Numpy matrices as values in Builder

    import kwant

    # For plotting
    from matplotlib import pyplot

77
78
79
.. jupyter-execute:: boilerplate.py
    :hide-code:

80
81
82
83
.. jupyter-execute::

    # For matrix support
    import tinyarray
84

Anton Akhmerov's avatar
Anton Akhmerov committed
85
For convenience, we define the Pauli-matrices first (with :math:`\sigma_0` the
86
87
unit matrix):

88
89
90
91
92
93
94
.. jupyter-execute::

    # define Pauli-matrices for convenience
    sigma_0 = tinyarray.array([[1, 0], [0, 1]])
    sigma_x = tinyarray.array([[0, 1], [1, 0]])
    sigma_y = tinyarray.array([[0, -1j], [1j, 0]])
    sigma_z = tinyarray.array([[1, 0], [0, -1]])
95

96
97
98
99
100
101
102
103
104
and we also define some other parameters useful for constructing our system:

.. jupyter-execute::

    t = 1.0
    alpha = 0.5
    e_z = 0.08
    W, L = 10, 30

105
106
107
108
Previously, we used numbers as the values of our matrix elements.
However, `~kwant.builder.Builder` also accepts matrices as values, and
we can simply write:

109
110
111
.. jupyter-execute::
    :hide-code:

112
    lat = kwant.lattice.square(norbs=2)
113
114
115
116
117
118
119
120
121
122
123
124
125
    syst = kwant.Builder()

.. jupyter-execute::

    #### Define the scattering region. ####
    syst[(lat(x, y) for x in range(L) for y in range(W))] = \
        4 * t * sigma_0 + e_z * sigma_z
    # hoppings in x-direction
    syst[kwant.builder.HoppingKind((1, 0), lat, lat)] = \
        -t * sigma_0 + 1j * alpha * sigma_y / 2
    # hoppings in y-directions
    syst[kwant.builder.HoppingKind((0, 1), lat, lat)] = \
        -t * sigma_0 - 1j * alpha * sigma_x / 2
126

127
128
129
Note that we specify ``norbs=2`` when creating the lattice, as each site
has 2 degrees of freedom associated with it, giving us 2x2 matrices as
onsite/hopping terms.
130
131
132
Note that the Zeeman energy adds to the onsite term, whereas the Rashba
spin-orbit term adds to the hoppings (due to the derivative operator).
Furthermore, the hoppings in x and y-direction have a different matrix
133
134
135
structure. We now cannot use ``lat.neighbors()`` to add all the hoppings at
once, since we now have to distinguish x and y-direction. Because of that, we
have to explicitly specify the hoppings in the form expected by
136
`~kwant.builder.HoppingKind`:
137
138
139
140
141

- A tuple with relative lattice indices.  For example, `(1, 0)` means
  hopping from `(i, j)` to `(i+1, j)`, whereas `(1, 1)` would
  mean hopping to `(i+1, j+1)`.
- The target lattice (where to hop to)
142
- The source lattice (where the hopping originates)
143
144
145
146
147
148
149
150
151
152
153

Since we are only dealing with a single lattice here, source and target
lattice are identical, but still must be specified  (for an example
with hopping between different (sub)lattices, see :ref:`tutorial-graphene`).

Again, it is enough to specify one direction of the hopping (i.e.
when specifying `(1, 0)` it is not necessary to specify `(-1, 0)`),
`~kwant.builder.Builder` assures hermiticity.

The leads also allow for a matrix structure,

154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

.. jupyter-execute::
    :hide-code:

    #### Define the left lead. ####
    lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))

.. jupyter-execute::

    lead[(lat(0, j) for j in range(W))] = 4 * t * sigma_0 + e_z * sigma_z
    # hoppings in x-direction
    lead[kwant.builder.HoppingKind((1, 0), lat, lat)] = \
        -t * sigma_0 + 1j * alpha * sigma_y / 2
    # hoppings in y-directions
    lead[kwant.builder.HoppingKind((0, 1), lat, lat)] = \
        -t * sigma_0 - 1j * alpha * sigma_x / 2

.. jupyter-execute::
    :hide-code:

    #### Attach the leads and finalize the system. ####
    syst.attach_lead(lead)
    syst.attach_lead(lead.reversed())
    syst = syst.finalized()
178
179
180
181

The remainder of the code is unchanged, and as a result we should obtain
the following, clearly non-monotonic conductance steps:

182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
.. jupyter-execute::
    :hide-code:

    # Compute conductance
    energies=[0.01 * i - 0.3 for i in range(100)]
    data = []
    for energy in energies:
        smatrix = kwant.smatrix(syst, energy)
        data.append(smatrix.transmission(1, 0))

    pyplot.figure()
    pyplot.plot(energies, data)
    pyplot.xlabel("energy [t]")
    pyplot.ylabel("conductance [e^2/h]")
    pyplot.show()
197
198
199

.. specialnote:: Technical details

200
201
  - The Tinyarray package, one of the dependencies of Kwant, implements
    efficient small arrays.  It is used internally in Kwant for storing small
202
    vectors and matrices.  For performance, it is preferable to define small
203
    arrays that are going to be used with Kwant using Tinyarray.  However,
204
205
206
207
208
209
210
211
    NumPy would work as well::

        import numpy
        sigma_0 = numpy.array([[1, 0], [0, 1]])
        sigma_x = numpy.array([[0, 1], [1, 0]])
        sigma_y = numpy.array([[0, -1j], [1j, 0]])
        sigma_z = numpy.array([[1, 0], [0, -1]])

212
    Tinyarray arrays behave for most purposes like NumPy arrays except that
213
    they are immutable: they cannot be changed once created.  This is important
214
    for Kwant: it allows them to be used directly as dictionary keys.
215

216
  - It should be emphasized that the relative hopping used for
217
    `~kwant.builder.HoppingKind` is given in terms of
218
219
    lattice indices, i.e. relative to the Bravais lattice vectors.
    For a square lattice, the Bravais lattice vectors are simply
220
    `(a,0)` and `(0,a)`, and hence the mapping from
221
    lattice indices `(i,j)` to real space and back is trivial.
222
    This becomes more involved in more complicated lattices, where
223
    the real-space directions corresponding to, for example, `(1,0)`
224
225
226
227
228
229
230
    and `(0,1)` need not be orthogonal any more
    (see :ref:`tutorial-graphene`).


Spatially dependent values through functions
............................................

231
232
.. seealso::
    The complete source code of this example can be found in
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
    :jupyter-download:script:`quantum_well`

.. jupyter-kernel::
    :id: quantum_well

.. jupyter-execute::
    :hide-code:

    # Tutorial 2.3.2. Spatially dependent values through functions
    # ============================================================
    #
    # Physics background
    # ------------------
    #  transmission through a quantum well
    #
    # Kwant features highlighted
    # --------------------------
    #  - Functions as values in Builder

    import kwant

    # For plotting
    from matplotlib import pyplot
256

257
258
259
.. jupyter-execute:: boilerplate.py
    :hide-code:

260
261
262
263
264
265
266
267
268
Up to now, all examples had position-independent matrix-elements
(and thus translational invariance along the wire, which
was the origin of the conductance steps). Now, we consider the
case of a position-dependent potential:

.. math::

    H = \frac{\hbar^2}{2 m} (\partial_x^2+\partial_y^2) + V(x, y)

Michael Wimmer's avatar
Michael Wimmer committed
269
270
271
The position-dependent potential enters in the onsite energies. One
possibility would be to again set the onsite matrix elements of each
lattice point individually (as in :ref:`tutorial_quantum_wire`). However,
272
273
274
275
276
changing the potential then implies the need to build up the system again.

Instead, we use a python *function* to define the onsite energies. We
define the potential profile of a quantum well as:

277
278
279
280
281
282
283
284
285
286
.. jupyter-execute::

    W, L, L_well = 10, 30, 10

    def potential(site, pot):
        (x, y) = site.pos
        if (L - L_well) / 2 < x < (L + L_well) / 2:
            return pot
        else:
            return 0
287

288
This function takes two arguments: the first of type `~kwant.system.Site`,
289
290
from which you can get the real-space coordinates using ``site.pos``, and the
value of the potential as the second.  Note that in `potential` we can access
291
variables `L` and `L_well` that are defined globally.
292

293
Kwant now allows us to pass a function as a value to
294
295
`~kwant.builder.Builder`:

296
297
.. jupyter-execute::

298
299
300
    a = 1
    t = 1.0

301
302
303
    def onsite(site, pot):
        return 4 * t + potential(site, pot)

304
    lat = kwant.lattice.square(a, norbs=1)
305
306
    syst = kwant.Builder()

307
308
309
310
311
312
313
314
315
316
317
318
319
320
    syst[(lat(x, y) for x in range(L) for y in range(W))] = onsite
    syst[lat.neighbors()] = -t

.. jupyter-execute::
    :hide-code:

    #### Define and attach the leads. ####
    lead = kwant.Builder(kwant.TranslationalSymmetry((-a, 0)))
    lead[(lat(0, j) for j in range(W))] = 4 * t
    lead[lat.neighbors()] = -t
    syst.attach_lead(lead)
    syst.attach_lead(lead.reversed())

    syst = syst.finalized()
321

322
For each lattice point, the corresponding site is then passed as the
323
first argument to the function `onsite`. The values of any additional
324
parameters, which can be used to alter the Hamiltonian matrix elements
325
at a later stage, are specified later during the call to `smatrix`.
326
Note that we had to define `onsite`, as it is
327
not possible to mix values and functions as in ``syst[...] = 4 * t +
328
329
330
331
332
333
334
335
336
potential``.

For the leads, we just use constant values as before. If we passed a
function also for the leads (which is perfectly allowed), this
function would need to be compatible with the translational symmetry
of the lead -- this should be kept in mind.

Finally, we compute the transmission probability:

337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
.. jupyter-execute::

    def plot_conductance(syst, energy, welldepths):

        # Compute conductance
        data = []
        for welldepth in welldepths:
            smatrix = kwant.smatrix(syst, energy, params=dict(pot=-welldepth))
            data.append(smatrix.transmission(1, 0))

        pyplot.figure()
        pyplot.plot(welldepths, data)
        pyplot.xlabel("well depth [t]")
        pyplot.ylabel("conductance [e^2/h]")
        pyplot.show()
352

353
354
355
356
357
358
``kwant.smatrix`` allows us to specify a dictionary, `params`, that contains
the additional arguments required by the Hamiltonian matrix elements.
In this example we are able to solve the system for different depths
of the potential well by passing the potential value (remember above
we defined our `onsite` function that takes a parameter named `pot`).
We obtain the result:
359

360
361
362
363
364
.. jupyter-execute::
    :hide-code:

    plot_conductance(syst, energy=0.2,
                     welldepths=[0.01 * i for i in range(100)])
365
366
367
368
369
370
371
372
373
374
375
376
377

Starting from no potential (well depth = 0), we observe the typical
oscillatory transmission behavior through resonances in the quantum well.

.. warning::

    If functions are used to set values inside a lead, then they must satisfy
    the same symmetry as the lead does.  There is (currently) no check and
    wrong results will be the consequence of a misbehaving function.

.. specialnote:: Technical details

  - Functions can also be used for hoppings. In this case, they take
378
    two `~kwant.system.Site`'s as arguments and then an arbitrary number
379
    of additional arguments.
380

381
  - Apart from the real-space position `pos`, `~kwant.system.Site` has also an
382
    attribute `tag` containing the lattice indices of the site.
383
384
385
386
387
388

.. _tutorial-abring:

Nontrivial shapes
.................

389
390
.. seealso::
    The complete source code of this example can be found in
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
    :jupyter-download:script:`ab_ring`

.. jupyter-kernel::
    :id: ab_ring

.. jupyter-execute::
    :hide-code:

    # Tutorial 2.3.3. Nontrivial shapes
    # =================================
    #
    # Physics background
    # ------------------
    #  Flux-dependent transmission through a quantum ring
    #
    # Kwant features highlighted
    # --------------------------
    #  - More complex shapes with lattices
    #  - Allows for discussion of subtleties of `attach_lead` (not in the
    #    example, but in the tutorial main text)
    #  - Modifcations of hoppings/sites after they have been added

    from cmath import exp
    from math import pi

    import kwant

    # For plotting
    from matplotlib import pyplot
420

421
422
423
.. jupyter-execute:: boilerplate.py
    :hide-code:

424
425
426
427
Up to now, we only dealt with simple wire geometries. Now we turn to the case
of a more complex geometry, namely transport through a quantum ring
that is pierced by a magnetic flux :math:`\Phi`:

428
.. image:: /figure/ab_ring_sketch.*
429
430
431
432
433
434
435
436
437
438
439
440
441

For a flux line, it is possible to choose a gauge such that a
charged particle acquires a phase :math:`e\Phi/h` whenever it
crosses the branch cut originating from the flux line (branch
cut shown as red dashed line) [#]_. There are more symmetric gauges, but
this one is most convenient to implement numerically.

Defining such a complex structure adding individual lattice sites
is possible, but cumbersome. Fortunately, there is a more convenient solution:
First, define a boolean function defining the desired shape, i.e. a function
that returns ``True`` whenever a point is inside the shape, and
``False`` otherwise:

442
443
444
445
446
447
448
449
.. jupyter-execute::

    r1, r2 = 10, 20

    def ring(pos):
        (x, y) = pos
        rsq = x ** 2 + y ** 2
        return (r1 ** 2 < rsq < r2 ** 2)
450

451
Note that this function takes a real-space position as argument (not a
452
`~kwant.system.Site`).
453
454
455
456
457

We can now simply add all of the lattice points inside this shape at
once, using the function `~kwant.lattice.Square.shape`
provided by the lattice:

458
459
.. jupyter-execute::

460
461
462
    a = 1
    t = 1.0

463
    lat = kwant.lattice.square(a, norbs=1)
464
465
    syst = kwant.Builder()

466
467
    syst[lat.shape(ring, (0, r1 + 1))] = 4 * t
    syst[lat.neighbors()] = -t
468

469
Here, ``lat.shape`` takes as a second parameter a (real-space) point that is
470
inside the desired shape. The hoppings can still be added using
471
``lat.neighbors()`` as before.
472
473
474
475
476

Up to now, the system contains constant hoppings and onsite energies,
and we still need to include the phase shift due to the magnetic flux.
This is done by **overwriting** the values of hoppings in x-direction
along the branch cut in the lower arm of the ring. For this we select
477
all hoppings in x-direction that are of the form `(lat(1, j), lat(0, j))`
478
479
with ``j<0``:

480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
.. jupyter-execute::

    # In order to introduce a flux through the ring, we introduce a phase on
    # the hoppings on the line cut through one of the arms.  Since we want to
    # change the flux without modifying the Builder instance repeatedly, we
    # define the modified hoppings as a function that takes the flux as its
    # parameter phi.
    def hopping_phase(site1, site2, phi):
        return -t * exp(1j * phi)

    def crosses_branchcut(hop):
        ix0, iy0 = hop[0].tag

        # builder.HoppingKind with the argument (1, 0) below
        # returns hoppings ordered as ((i+1, j), (i, j))
        return iy0 < 0 and ix0 == 1  # ix1 == 0 then implied

    # Modify only those hopings in x-direction that cross the branch cut
    def hops_across_cut(syst):
        for hop in kwant.builder.HoppingKind((1, 0), lat, lat)(syst):
            if crosses_branchcut(hop):
                yield hop

    syst[hops_across_cut] = hopping_phase
504
505
506
507
508
509
510
511

Here, `crosses_branchcut` is a boolean function that returns ``True`` for
the desired hoppings. We then use again a generator (this time with
an ``if``-conditional) to set the value of all hoppings across
the branch cut to `fluxphase`. The rationale
behind using a function instead of a constant value for the hopping
is again that we want to vary the flux through the ring, without
constantly rebuilding the system -- instead the flux is governed
512
by the parameter `phi`.
513

514
For the leads, we can also use the ``lat.shape``-functionality:
515

516
517
518
.. jupyter-execute::

    #### Define the leads. ####
519
520
    W = 10

521
522
523
    sym_lead = kwant.TranslationalSymmetry((-a, 0))
    lead = kwant.Builder(sym_lead)

524

525
526
527
528
529
530
    def lead_shape(pos):
        (x, y) = pos
        return (-W / 2 < y < W / 2)

    lead[lat.shape(lead_shape, (0, 0))] = 4 * t
    lead[lat.neighbors()] = -t
531

532
533
534
535
Here, the shape must be compatible with the translational symmetry
of the lead ``sym_lead``. In particular, this means that it should extend to
infinity along the translational symmetry direction (note how there is
no restriction on ``x`` in ``lead_shape``) [#]_.
536
537
538

Attaching the leads is done as before:

539
540
541
542
543
544
.. jupyter-execute::
    :hide-output:

    #### Attach the leads ####
    syst.attach_lead(lead)
    syst.attach_lead(lead.reversed())
545
546
547
548

In fact, attaching leads seems not so simple any more for the current
structure with a scattering region very much different from the lead
shapes. However, the choice of unit cell together with the
549
translational vector allows to place the lead unambiguously in real space --
550
551
the unit cell is repeated infinitely many times in the direction and
opposite to the direction of the translational vector.
552
Kwant examines the lead starting from infinity and traces it
553
554
555
556
back (going opposite to the direction of the translational vector)
until it intersects the scattering region. At this intersection,
the lead is attached:

557
.. image:: /figure/ab_ring_sketch2.*
558
559
560

After the lead has been attached, the system should look like this:

561
562
563
564
.. jupyter-execute::
    :hide-code:

    kwant.plot(syst);
565
566
567
568

The computation of the conductance goes in the same fashion as before.
Finally you should get the following result:

569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590

.. jupyter-execute::
    :hide-code:

    def plot_conductance(syst, energy, fluxes):
        # compute conductance

        normalized_fluxes = [flux / (2 * pi) for flux in fluxes]
        data = []
        for flux in fluxes:
            smatrix = kwant.smatrix(syst, energy, params=dict(phi=flux))
            data.append(smatrix.transmission(1, 0))

        pyplot.figure()
        pyplot.plot(normalized_fluxes, data)
        pyplot.xlabel("flux [flux quantum]")
        pyplot.ylabel("conductance [e^2/h]")
        pyplot.show()

    # We should see a conductance that is periodic with the flux quantum
    plot_conductance(syst.finalized(), energy=0.15,
                     fluxes=[0.01 * i * 3 * 2 * pi for i in range(100)])
591
592
593
594
595
596

where one can observe the conductance oscillations with the
period of one flux quantum.

.. specialnote:: Technical details

597
  - Leads have to have proper periodicity. Furthermore, the Kwant
598
599
600
601
602
603
604
605
    format requires the hopping from the leads to the scattering
    region to be identical to the hoppings between unit cells in
    the lead. `~kwant.builder.Builder.attach_lead` takes care of
    all these details for you! In fact, it even adds points to
    the scattering region, if proper attaching requires this. This
    becomes more apparent if we attach the leads a bit further away
    from the central axis o the ring, as was done in this example:

606
607
608
609
610
611
612
613
614
    .. jupyter-kernel::
        :id: ab_ring_note1

    .. jupyter-execute::
        :hide-code:

        import kwant
        from matplotlib import pyplot

615
616
617
618
619
620
    .. jupyter-execute:: boilerplate.py
        :hide-code:

    .. jupyter-execute::
        :hide-code:

621
622
623
624
625
        a = 1
        t = 1.0
        W = 10
        r1, r2 = 10, 20

626
        lat = kwant.lattice.square(norbs=1)
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
        syst = kwant.Builder()
        def ring(pos):
            (x, y) = pos
            rsq = x**2 + y**2
            return ( r1**2 < rsq < r2**2)
        syst[lat.shape(ring, (0, 11))] = 4 * t
        syst[lat.neighbors()] = -t
        sym_lead0 = kwant.TranslationalSymmetry((-a, 0))
        lead0 = kwant.Builder(sym_lead0)
        def lead_shape(pos):
            (x, y) = pos
            return (-1 < x < 1) and ( 0.5 * W < y < 1.5 * W )
        lead0[lat.shape(lead_shape, (0, W))] = 4 * t
        lead0[lat.neighbors()] = -t
        lead1 = lead0.reversed()
        syst.attach_lead(lead0)
        syst.attach_lead(lead1)

        kwant.plot(syst);

647
648
649
650
651
652
653
654
655

  - Per default, `~kwant.builder.Builder.attach_lead` attaches
    the lead to the "outside" of the structure, by tracing the
    lead backwards, coming from infinity.

    One can also attach the lead to the inside of the structure,
    by providing an alternative starting point from where
    the lead is traced back::

656
        syst.attach_lead(lead1, lat(0, 0))
657
658
659
660

    starts the trace-back in the middle of the ring, resulting
    in the lead being attached to the inner circle:

661
662
663
664
665
666
667
668
669
    .. jupyter-kernel::
        :id: ab_ring_note2

    .. jupyter-execute::
        :hide-code:

        import kwant
        from matplotlib import pyplot

670
671
672
673
674
675
    .. jupyter-execute:: boilerplate.py
        :hide-code:

    .. jupyter-execute::
        :hide-code:

676
677
678
679
680
        a = 1
        t = 1.0
        W = 10
        r1, r2 = 10, 20

681
        lat = kwant.lattice.square(a, norbs=1)
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
        syst = kwant.Builder()
        def ring(pos):
            (x, y) = pos
            rsq = x**2 + y**2
            return ( r1**2 < rsq < r2**2)
        syst[lat.shape(ring, (0, 11))] = 4 * t
        syst[lat.neighbors()] = -t
        sym_lead0 = kwant.TranslationalSymmetry((-a, 0))
        lead0 = kwant.Builder(sym_lead0)
        def lead_shape(pos):
            (x, y) = pos
            return (-1 < x < 1) and ( -W/2 < y < W/2  )
        lead0[lat.shape(lead_shape, (0, 0))] = 4 * t
        lead0[lat.neighbors()] = -t
        lead1 = lead0.reversed()
        syst.attach_lead(lead0)
        syst.attach_lead(lead1, lat(0, 0))

        kwant.plot(syst);
701
702
703
704
705
706
707
708
709

    Note that here the lead is treated as if it would pass over
    the other arm of the ring, without intersecting it.

.. rubric:: Footnotes

.. [#] The corresponding vector potential is :math:`A_x(x,y)=\Phi \delta(x)
       \Theta(-y)` which yields the correct magnetic field :math:`B(x,y)=\Phi
       \delta(x)\delta(y)`.
710
711
.. [#] Despite the "infinite" shape, the unit cell will still be finite; the
       `~kwant.lattice.TranslationalSymmetry` takes care of that.