1
+ # -*- coding: utf-8 -*-
1
2
import inspect
2
3
import operator
3
4
import sys
9
10
import kwant
10
11
import numpy as np
11
12
import scipy .constants
13
+ import scipy .sparse
14
+ import scipy .sparse .linalg as sla
12
15
from kwant .continuum .discretizer import discretize
13
16
14
17
import pfaffian as pf
@@ -111,15 +114,15 @@ def parse_params(params):
111
114
112
115
113
116
@memoize
114
- def discretized_hamiltonian (a , which_lead = None ):
117
+ def discretized_hamiltonian (a , which_lead = None , subst_sm = None ):
115
118
ham = (
116
119
"(0.5 * hbar**2 * (k_x**2 + k_y**2 + k_z**2) / m_eff * c - mu + V) * kron(sigma_0, sigma_z) + "
117
120
"alpha * (k_y * kron(sigma_x, sigma_z) - k_x * kron(sigma_y, sigma_z)) + "
118
121
"0.5 * g * mu_B * (B_x * kron(sigma_x, sigma_0) + B_y * kron(sigma_y, sigma_0) + B_z * kron(sigma_z, sigma_0)) + "
119
122
"Delta * kron(sigma_0, sigma_x)"
120
123
)
121
-
122
- subst_sm = {"Delta" : 0 }
124
+ if subst_sm is None :
125
+ subst_sm = {"Delta" : 0 }
123
126
124
127
if which_lead is not None :
125
128
subst_sm ["V" ] = f"V_{ which_lead } (z, V_0, V_r, V_l, x0, sigma, r1)"
@@ -274,7 +277,7 @@ def change_hopping_at_interface(syst, template, shape1, shape2):
274
277
275
278
276
279
@memoize
277
- def make_lead (a , r1 , r2 , coverage_angle , angle , with_shell , which_lead ):
280
+ def make_lead (a , r1 , r2 , coverage_angle , angle , with_shell , which_lead , sc_inside_wire = False , wraparound = False ):
278
281
"""Create an infinite cylindrical 3D wire partially covered with a
279
282
superconducting (SC) shell.
280
283
@@ -297,6 +300,10 @@ def make_lead(a, r1, r2, coverage_angle, angle, with_shell, which_lead):
297
300
Name of the potential function of the lead, e.g. `which_lead = 'left'` will
298
301
require a function `V_left(z, V_0)` and
299
302
`mu_left(mu_func(x, x0, sigma, mu_lead, mu_wire)`.
303
+ sc_inside_wire : bool
304
+ Put superconductivity inside the wire.
305
+ wraparound : bool
306
+ Apply wraparound to the lead.
300
307
301
308
Returns
302
309
-------
@@ -326,7 +333,7 @@ def make_lead(a, r1, r2, coverage_angle, angle, with_shell, which_lead):
326
333
)
327
334
328
335
templ_sm , templ_sc , templ_interface = discretized_hamiltonian (
329
- a , which_lead = which_lead
336
+ a , which_lead = which_lead , subst_sm = {} if sc_inside_wire else None
330
337
)
331
338
templ_sm = apply_peierls_to_template (templ_sm )
332
339
lead .fill (templ_sm , * shape_normal_lead )
@@ -339,7 +346,6 @@ def make_lead(a, r1, r2, coverage_angle, angle, with_shell, which_lead):
339
346
340
347
xyz_offset = get_offset (* shape_sc , lat )
341
348
342
- templ_sc = apply_peierls_to_template (templ_sc , xyz_offset = xyz_offset )
343
349
templ_interface = apply_peierls_to_template (templ_interface )
344
350
lead .fill (templ_sc , * shape_sc_lead )
345
351
@@ -348,6 +354,8 @@ def make_lead(a, r1, r2, coverage_angle, angle, with_shell, which_lead):
348
354
lead , templ_interface , shape_normal_lead , shape_sc_lead
349
355
)
350
356
357
+ if wraparound :
358
+ lead = kwant .wraparound .wraparound (lead )
351
359
return lead
352
360
353
361
@@ -474,3 +482,45 @@ def gap_from_modes(lead, params, tol=1e-6):
474
482
lim [0 ] = energy
475
483
gap = sum (lim ) / 2
476
484
return gap
485
+
486
+
487
+ def phase_bounds_operator (lead , params , k_x = 0 , mu_param = 'mu' ):
488
+ params = dict (params , k_x = k_x )
489
+ params [mu_param ] = 0
490
+ h_k = lead .hamiltonian_submatrix (params = params , sparse = True )
491
+ sigma_z = scipy .sparse .csc_matrix (np .array ([[1 , 0 ], [0 , - 1 ]]))
492
+ _operator = scipy .sparse .kron (scipy .sparse .eye (h_k .shape [0 ] // 2 ), sigma_z ) @ h_k
493
+ return _operator
494
+
495
+
496
+ def find_phase_bounds (lead , params , k_x = 0 , num_bands = 20 , sigma = 0 , mu_param = 'mu' ):
497
+ """Find the phase boundaries.
498
+ Solve an eigenproblem that finds values of chemical potential at which the
499
+ gap closes at momentum k=0. We are looking for all real solutions of the
500
+ form H*psi=0 so we solve sigma_0 * tau_z H * psi = mu * psi.
501
+
502
+ Parameters
503
+ -----------
504
+ lead : kwant.builder.InfiniteSystem object
505
+ The finalized infinite system.
506
+ params : dict
507
+ A dictionary that is used to store Hamiltonian parameters.
508
+ k_x : float
509
+ Momentum value, by default set to 0.
510
+
511
+ Returns
512
+ --------
513
+ chemical_potential : numpy array
514
+ Twenty values of chemical potential at which a bandgap closes at k=0.
515
+ """
516
+ chemical_potentials = phase_bounds_operator (lead , params , k_x , mu_param )
517
+
518
+ if num_bands is None :
519
+ mus = np .linalg .eigvals (chemical_potentials .todense ())
520
+ else :
521
+ mus = sla .eigs (chemical_potentials , k = num_bands , sigma = sigma , which = "LM" )[0 ]
522
+
523
+ real_solutions = abs (np .angle (mus )) < 1e-10
524
+
525
+ mus [~ real_solutions ] = np .nan # To ensure it returns the same shape vector
526
+ return np .sort (mus .real )
0 commit comments