Skip to content

Commit 76d9d2d

Browse files
committedNov 19, 2019
fix phase diagram code
1 parent f1a8300 commit 76d9d2d

File tree

2 files changed

+134
-23
lines changed

2 files changed

+134
-23
lines changed
 

‎phase_diagram.ipynb

+78-17
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"from functools import partial\n",
1313
"\n",
1414
"import phase_diagram\n",
15+
"\n",
1516
"lead_pars = dict(\n",
1617
" a=10, r1=50, r2=70, coverage_angle=135, angle=45, with_shell=True, which_lead=\"\"\n",
1718
")\n",
@@ -27,7 +28,6 @@
2728
" mu_sc=100,\n",
2829
" c_tunnel=3 / 4,\n",
2930
" V_r=-50,\n",
30-
" intrinsic_sc=False,\n",
3131
" mu_=\"lambda x0, sigma, mu_lead, mu_wire: mu_lead\",\n",
3232
" V_=\"lambda z, V_0, V_r, V_l, x0, sigma, r1: 0\",\n",
3333
" V_0=None,\n",
@@ -42,7 +42,7 @@
4242
"\n",
4343
"\n",
4444
"def pf(xy, params=params, lead_pars=lead_pars):\n",
45-
" import phase_diagram \n",
45+
" import phase_diagram\n",
4646
"\n",
4747
" params[\"B_x\"], params[\"mu_lead\"] = xy\n",
4848
" lead = phase_diagram.make_lead(**lead_pars).finalized()\n",
@@ -60,24 +60,43 @@
6060
" return pf * gap\n",
6161
"\n",
6262
"\n",
63-
"fnames = ['phase_diagram_gap.pickle', 'phase_diagram_gap_no_orbital.pickle']\n",
63+
"fnames = [\n",
64+
"# \"phase_diagram_gap.pickle\",\n",
65+
"# \"phase_diagram_gap_no_orbital.pickle\",\n",
66+
"# \"phase_diagram_gap_sc_inside.pickle\",\n",
67+
" \"phase_diagram_gap_sc_inside_no_orbital.pickle\",\n",
68+
"]\n",
6469
"loss = adaptive.learner.learnerND.curvature_loss_function()\n",
6570
"\n",
6671
"learners = []\n",
67-
"for orbital in [True, False]:\n",
68-
" f = partial(smallest_gap, params=dict(params, orbital=orbital))\n",
69-
" learners.append(adaptive.Learner2D(f, bounds=[(0, 2), (0, 35)],\n",
70-
"# loss_per_simplex=loss,\n",
71-
" ))\n",
72-
"learner = adaptive.BalancingLearner(learners, strategy='npoints')\n",
73-
"# fname = 'phase_diagram_gap.pickle'\n",
74-
"# learner = adaptive.LearnerND(smallest_gap, bounds=[(0, 2), (0, 35)], loss_per_simplex=loss)\n",
75-
"# learners = [learner]\n",
76-
"# fnames = [fname]\n",
72+
"for sc_inside_wire, orbital, Delta in (\n",
73+
"# [False, True, 110],\n",
74+
"# [False, False, 110],\n",
75+
"# [True, True, 0.25],\n",
76+
" [True, False, 0.25],\n",
77+
"):\n",
78+
" f = partial(\n",
79+
" smallest_gap,\n",
80+
" params=dict(params, orbital=orbital, Delta=Delta),\n",
81+
" lead_pars=dict(\n",
82+
" lead_pars, sc_inside_wire=sc_inside_wire, with_shell=(not sc_inside_wire)\n",
83+
" ),\n",
84+
" )\n",
85+
" learners.append(adaptive.Learner2D(f, bounds=[(0, 2), (0, 35)]))\n",
86+
"learner = adaptive.BalancingLearner(learners, strategy=\"npoints\")\n",
7787
"\n",
7888
"learner.load(fnames)"
7989
]
8090
},
91+
{
92+
"cell_type": "code",
93+
"execution_count": null,
94+
"metadata": {},
95+
"outputs": [],
96+
"source": [
97+
"from learners_file import *"
98+
]
99+
},
81100
{
82101
"cell_type": "code",
83102
"execution_count": null,
@@ -87,7 +106,7 @@
87106
"import adaptive\n",
88107
"\n",
89108
"adaptive.notebook_extension()\n",
90-
"runner = adaptive.Runner(learner, goal=lambda l: l.learners[1].npoints > 60000)\n",
109+
"runner = adaptive.Runner(learner, goal=lambda l: l.learners[-1].npoints > 20000)\n",
91110
"runner.live_info()"
92111
]
93112
},
@@ -97,7 +116,27 @@
97116
"metadata": {},
98117
"outputs": [],
99118
"source": [
100-
"adap"
119+
"import kwant\n",
120+
"%matplotlib inline\n",
121+
"kwant.plot(phase_diagram.make_lead(**f.keywords['lead_pars']))"
122+
]
123+
},
124+
{
125+
"cell_type": "code",
126+
"execution_count": null,
127+
"metadata": {},
128+
"outputs": [],
129+
"source": [
130+
"runner.start_periodic_saving(dict(fname=fnames), 900)"
131+
]
132+
},
133+
{
134+
"cell_type": "code",
135+
"execution_count": null,
136+
"metadata": {},
137+
"outputs": [],
138+
"source": [
139+
"learners[0].plot(n=200, tri_alpha=0.2).Image.I[:, 6:]"
101140
]
102141
},
103142
{
@@ -135,7 +174,8 @@
135174
"metadata": {},
136175
"outputs": [],
137176
"source": [
138-
"learners[1].save(fnames[1])"
177+
"for l, f in zip(learners, fnames):\n",
178+
" l.save(f)"
139179
]
140180
},
141181
{
@@ -170,7 +210,28 @@
170210
"execution_count": null,
171211
"metadata": {},
172212
"outputs": [],
173-
"source": []
213+
"source": [
214+
"from learners_file import *"
215+
]
216+
},
217+
{
218+
"cell_type": "code",
219+
"execution_count": null,
220+
"metadata": {},
221+
"outputs": [],
222+
"source": [
223+
"adaptive.notebook_extension()"
224+
]
225+
},
226+
{
227+
"cell_type": "code",
228+
"execution_count": null,
229+
"metadata": {},
230+
"outputs": [],
231+
"source": [
232+
"learner = learners[0]\n",
233+
"learner.plot(n=100)"
234+
]
174235
}
175236
],
176237
"metadata": {

‎phase_diagram.py

+56-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: utf-8 -*-
12
import inspect
23
import operator
34
import sys
@@ -9,6 +10,8 @@
910
import kwant
1011
import numpy as np
1112
import scipy.constants
13+
import scipy.sparse
14+
import scipy.sparse.linalg as sla
1215
from kwant.continuum.discretizer import discretize
1316

1417
import pfaffian as pf
@@ -111,15 +114,15 @@ def parse_params(params):
111114

112115

113116
@memoize
114-
def discretized_hamiltonian(a, which_lead=None):
117+
def discretized_hamiltonian(a, which_lead=None, subst_sm=None):
115118
ham = (
116119
"(0.5 * hbar**2 * (k_x**2 + k_y**2 + k_z**2) / m_eff * c - mu + V) * kron(sigma_0, sigma_z) + "
117120
"alpha * (k_y * kron(sigma_x, sigma_z) - k_x * kron(sigma_y, sigma_z)) + "
118121
"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)) + "
119122
"Delta * kron(sigma_0, sigma_x)"
120123
)
121-
122-
subst_sm = {"Delta": 0}
124+
if subst_sm is None:
125+
subst_sm = {"Delta": 0}
123126

124127
if which_lead is not None:
125128
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):
274277

275278

276279
@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):
278281
"""Create an infinite cylindrical 3D wire partially covered with a
279282
superconducting (SC) shell.
280283
@@ -297,6 +300,10 @@ def make_lead(a, r1, r2, coverage_angle, angle, with_shell, which_lead):
297300
Name of the potential function of the lead, e.g. `which_lead = 'left'` will
298301
require a function `V_left(z, V_0)` and
299302
`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.
300307
301308
Returns
302309
-------
@@ -326,7 +333,7 @@ def make_lead(a, r1, r2, coverage_angle, angle, with_shell, which_lead):
326333
)
327334

328335
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
330337
)
331338
templ_sm = apply_peierls_to_template(templ_sm)
332339
lead.fill(templ_sm, *shape_normal_lead)
@@ -339,7 +346,6 @@ def make_lead(a, r1, r2, coverage_angle, angle, with_shell, which_lead):
339346

340347
xyz_offset = get_offset(*shape_sc, lat)
341348

342-
templ_sc = apply_peierls_to_template(templ_sc, xyz_offset=xyz_offset)
343349
templ_interface = apply_peierls_to_template(templ_interface)
344350
lead.fill(templ_sc, *shape_sc_lead)
345351

@@ -348,6 +354,8 @@ def make_lead(a, r1, r2, coverage_angle, angle, with_shell, which_lead):
348354
lead, templ_interface, shape_normal_lead, shape_sc_lead
349355
)
350356

357+
if wraparound:
358+
lead = kwant.wraparound.wraparound(lead)
351359
return lead
352360

353361

@@ -474,3 +482,45 @@ def gap_from_modes(lead, params, tol=1e-6):
474482
lim[0] = energy
475483
gap = sum(lim) / 2
476484
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

Comments
 (0)
Please sign in to comment.