quant-met 0.0.5__py3-none-any.whl → 0.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quant_met/geometry/__init__.py +26 -0
- quant_met/geometry/base_lattice.py +85 -0
- quant_met/geometry/bz_path.py +89 -0
- quant_met/geometry/graphene.py +39 -0
- quant_met/geometry/square.py +38 -0
- quant_met/mean_field/__init__.py +4 -0
- quant_met/mean_field/base_hamiltonian.py +94 -11
- quant_met/mean_field/eg_x.py +23 -15
- quant_met/mean_field/free_energy.py +1 -1
- quant_met/mean_field/graphene.py +40 -31
- quant_met/mean_field/one_band_tight_binding.py +129 -0
- quant_met/mean_field/quantum_metric.py +23 -24
- quant_met/mean_field/self_consistency.py +39 -0
- quant_met/plotting/__init__.py +13 -3
- quant_met/plotting/plotting.py +94 -76
- {quant_met-0.0.5.dist-info → quant_met-0.0.7.dist-info}/METADATA +15 -7
- quant_met-0.0.7.dist-info/RECORD +24 -0
- {quant_met-0.0.5.dist-info → quant_met-0.0.7.dist-info}/WHEEL +1 -1
- quant_met-0.0.5.dist-info/RECORD +0 -17
- {quant_met-0.0.5.dist-info → quant_met-0.0.7.dist-info}/LICENSE.txt +0 -0
- {quant_met-0.0.5.dist-info → quant_met-0.0.7.dist-info}/LICENSES/MIT.txt +0 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""
|
6
|
+
Geometry (:mod:`quant_met.geometry`)
|
7
|
+
========
|
8
|
+
|
9
|
+
.. currentmodule:: quant_met.geometry
|
10
|
+
|
11
|
+
Functions
|
12
|
+
---------
|
13
|
+
|
14
|
+
.. autosummary::
|
15
|
+
:toctree: generated/
|
16
|
+
|
17
|
+
generate_bz_path
|
18
|
+
Graphene
|
19
|
+
""" # noqa: D205, D400
|
20
|
+
|
21
|
+
from .base_lattice import BaseLattice
|
22
|
+
from .bz_path import generate_bz_path
|
23
|
+
from .graphene import Graphene
|
24
|
+
from .square import SquareLattice
|
25
|
+
|
26
|
+
__all__ = ["generate_bz_path", "BaseLattice", "Graphene", "SquareLattice"]
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Base class for lattice geometries."""
|
6
|
+
|
7
|
+
from abc import ABC, abstractmethod
|
8
|
+
|
9
|
+
import numpy as np
|
10
|
+
import numpy.typing as npt
|
11
|
+
|
12
|
+
from quant_met.utils import generate_uniform_grid
|
13
|
+
|
14
|
+
from .bz_path import generate_bz_path
|
15
|
+
|
16
|
+
|
17
|
+
class BaseLattice(ABC):
|
18
|
+
"""Base class for lattice geometries."""
|
19
|
+
|
20
|
+
@property
|
21
|
+
@abstractmethod
|
22
|
+
def lattice_constant(self) -> np.float64:
|
23
|
+
"""Lattice constant."""
|
24
|
+
raise NotImplementedError
|
25
|
+
|
26
|
+
@property
|
27
|
+
@abstractmethod
|
28
|
+
def bz_corners(self) -> npt.NDArray[np.float64]:
|
29
|
+
"""Corners of the BZ."""
|
30
|
+
raise NotImplementedError
|
31
|
+
|
32
|
+
@property
|
33
|
+
@abstractmethod
|
34
|
+
def high_symmetry_points(self) -> tuple[tuple[npt.NDArray[np.float64], str], ...]:
|
35
|
+
"""Tuple of high symmetry points and names."""
|
36
|
+
raise NotImplementedError
|
37
|
+
|
38
|
+
def generate_bz_grid(self, ncols: int, nrows: int) -> npt.NDArray[np.float64]:
|
39
|
+
"""Generate a grid in the BZ.
|
40
|
+
|
41
|
+
Parameters
|
42
|
+
----------
|
43
|
+
ncols : int
|
44
|
+
Number of points in column.
|
45
|
+
nrows : int
|
46
|
+
Number of points in row.
|
47
|
+
|
48
|
+
Returns
|
49
|
+
-------
|
50
|
+
:class:`numpy.ndarray`
|
51
|
+
Array of grid points in the BZ.
|
52
|
+
|
53
|
+
"""
|
54
|
+
return generate_uniform_grid(
|
55
|
+
ncols, nrows, self.bz_corners[0], self.bz_corners[1], origin=np.array([0, 0])
|
56
|
+
)
|
57
|
+
|
58
|
+
def generate_high_symmetry_path(
|
59
|
+
self, number_of_points: int
|
60
|
+
) -> tuple[
|
61
|
+
npt.NDArray[np.float64],
|
62
|
+
npt.NDArray[np.float64],
|
63
|
+
list[float],
|
64
|
+
list[str],
|
65
|
+
]:
|
66
|
+
"""Generate a path through high symmetry points.
|
67
|
+
|
68
|
+
Parameters
|
69
|
+
----------
|
70
|
+
number_of_points: int
|
71
|
+
Number of point in the whole path.
|
72
|
+
|
73
|
+
Returns
|
74
|
+
-------
|
75
|
+
:class:`numpy.ndarray`
|
76
|
+
List of two-dimensional k points.
|
77
|
+
:class:`numpy.ndarray`
|
78
|
+
Path for plotting purposes: points between 0 and 1, with appropriate spacing.
|
79
|
+
list[float]
|
80
|
+
A list of ticks for the plotting path.
|
81
|
+
list[str]
|
82
|
+
A list of labels for the plotting path.
|
83
|
+
|
84
|
+
"""
|
85
|
+
return generate_bz_path(list(self.high_symmetry_points), number_of_points=number_of_points)
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Methods to generate paths through the BZ."""
|
6
|
+
|
7
|
+
import numpy as np
|
8
|
+
import numpy.typing as npt
|
9
|
+
|
10
|
+
|
11
|
+
def _generate_part_of_path(
|
12
|
+
p_0: npt.NDArray[np.float64],
|
13
|
+
p_1: npt.NDArray[np.float64],
|
14
|
+
n: int,
|
15
|
+
length_whole_path: int,
|
16
|
+
) -> npt.NDArray[np.float64]:
|
17
|
+
distance = np.linalg.norm(p_1 - p_0)
|
18
|
+
number_of_points = int(n * distance / length_whole_path) + 1
|
19
|
+
|
20
|
+
return np.vstack(
|
21
|
+
[
|
22
|
+
np.linspace(p_0[0], p_1[0], number_of_points),
|
23
|
+
np.linspace(p_0[1], p_1[1], number_of_points),
|
24
|
+
]
|
25
|
+
).T[:-1]
|
26
|
+
|
27
|
+
|
28
|
+
def generate_bz_path(
|
29
|
+
points: list[tuple[npt.NDArray[np.float64], str]], number_of_points: int = 1000
|
30
|
+
) -> tuple[
|
31
|
+
npt.NDArray[np.float64],
|
32
|
+
npt.NDArray[np.float64],
|
33
|
+
list[float],
|
34
|
+
list[str],
|
35
|
+
]:
|
36
|
+
"""Generate a path through high symmetry points.
|
37
|
+
|
38
|
+
Parameters
|
39
|
+
----------
|
40
|
+
points : :class:`numpy.ndarray`
|
41
|
+
Test
|
42
|
+
number_of_points: int
|
43
|
+
Number of point in the whole path.
|
44
|
+
|
45
|
+
Returns
|
46
|
+
-------
|
47
|
+
:class:`numpy.ndarray`
|
48
|
+
List of two-dimensional k points.
|
49
|
+
:class:`numpy.ndarray`
|
50
|
+
Path for plotting purposes: points between 0 and 1, with appropriate spacing.
|
51
|
+
list[float]
|
52
|
+
A list of ticks for the plotting path.
|
53
|
+
list[str]
|
54
|
+
A list of labels for the plotting path.
|
55
|
+
|
56
|
+
"""
|
57
|
+
n = number_of_points
|
58
|
+
|
59
|
+
cycle = [np.linalg.norm(points[i][0] - points[i + 1][0]) for i in range(len(points) - 1)]
|
60
|
+
cycle.append(np.linalg.norm(points[-1][0] - points[0][0]))
|
61
|
+
|
62
|
+
length_whole_path = np.sum(np.array([cycle]))
|
63
|
+
|
64
|
+
ticks = [0.0]
|
65
|
+
ticks.extend([np.sum(cycle[0 : i + 1]) / length_whole_path for i in range(len(cycle) - 1)])
|
66
|
+
ticks.append(1.0)
|
67
|
+
labels = [rf"${points[i][1]}$" for i in range(len(points))]
|
68
|
+
labels.append(rf"${points[0][1]}$")
|
69
|
+
|
70
|
+
whole_path_plot = np.concatenate(
|
71
|
+
[
|
72
|
+
np.linspace(
|
73
|
+
ticks[i],
|
74
|
+
ticks[i + 1],
|
75
|
+
num=int(n * cycle[i] / length_whole_path),
|
76
|
+
endpoint=False,
|
77
|
+
)
|
78
|
+
for i in range(len(ticks) - 1)
|
79
|
+
]
|
80
|
+
)
|
81
|
+
|
82
|
+
points_path = [
|
83
|
+
_generate_part_of_path(points[i][0], points[i + 1][0], n, length_whole_path)
|
84
|
+
for i in range(len(points) - 1)
|
85
|
+
]
|
86
|
+
points_path.append(_generate_part_of_path(points[-1][0], points[0][0], n, length_whole_path))
|
87
|
+
whole_path = np.concatenate(points_path)
|
88
|
+
|
89
|
+
return whole_path, whole_path_plot, ticks, labels
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Lattice geometry for Graphene."""
|
6
|
+
|
7
|
+
import numpy as np
|
8
|
+
import numpy.typing as npt
|
9
|
+
|
10
|
+
from .base_lattice import BaseLattice
|
11
|
+
|
12
|
+
|
13
|
+
class Graphene(BaseLattice):
|
14
|
+
"""Lattice geometry for Graphene."""
|
15
|
+
|
16
|
+
def __init__(self, lattice_constant: np.float64) -> None:
|
17
|
+
self._lattice_constant = lattice_constant
|
18
|
+
self._bz_corners = (
|
19
|
+
4
|
20
|
+
* np.pi
|
21
|
+
/ (3 * self.lattice_constant)
|
22
|
+
* np.array([(np.cos(i * np.pi / 3), np.sin(i * np.pi / 3)) for i in range(6)])
|
23
|
+
)
|
24
|
+
self.Gamma = np.array([0, 0])
|
25
|
+
self.M = np.pi / self.lattice_constant * np.array([1, 1 / np.sqrt(3)])
|
26
|
+
self.K = 4 * np.pi / (3 * self.lattice_constant) * np.array([1, 0])
|
27
|
+
self._high_symmetry_points = ((self.M, "M"), (self.Gamma, r"\Gamma"), (self.K, "K"))
|
28
|
+
|
29
|
+
@property
|
30
|
+
def lattice_constant(self) -> np.float64: # noqa: D102
|
31
|
+
return self._lattice_constant
|
32
|
+
|
33
|
+
@property
|
34
|
+
def bz_corners(self) -> npt.NDArray[np.float64]: # noqa: D102
|
35
|
+
return self._bz_corners
|
36
|
+
|
37
|
+
@property
|
38
|
+
def high_symmetry_points(self) -> tuple[tuple[npt.NDArray[np.float64], str], ...]: # noqa: D102
|
39
|
+
return self._high_symmetry_points
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Lattice geometry for Square Lattice."""
|
6
|
+
|
7
|
+
import numpy as np
|
8
|
+
import numpy.typing as npt
|
9
|
+
|
10
|
+
from .base_lattice import BaseLattice
|
11
|
+
|
12
|
+
|
13
|
+
class SquareLattice(BaseLattice):
|
14
|
+
"""Lattice geometry for Square Lattice."""
|
15
|
+
|
16
|
+
def __init__(self, lattice_constant: np.float64) -> None:
|
17
|
+
self._lattice_constant = lattice_constant
|
18
|
+
self._bz_corners = (
|
19
|
+
np.pi
|
20
|
+
/ lattice_constant
|
21
|
+
* np.array([np.array([1, 1]), np.array([-1, 1]), np.array([1, -1]), np.array([-1, -1])])
|
22
|
+
)
|
23
|
+
self.Gamma = np.array([0, 0])
|
24
|
+
self.M = np.pi / lattice_constant * np.array([1, 1])
|
25
|
+
self.X = np.pi / lattice_constant * np.array([1, 0])
|
26
|
+
self._high_symmetry_points = ((self.Gamma, r"\Gamma"), (self.M, "M"))
|
27
|
+
|
28
|
+
@property
|
29
|
+
def lattice_constant(self) -> np.float64: # noqa: D102
|
30
|
+
return self._lattice_constant
|
31
|
+
|
32
|
+
@property
|
33
|
+
def bz_corners(self) -> npt.NDArray[np.float64]: # noqa: D102
|
34
|
+
return self._bz_corners
|
35
|
+
|
36
|
+
@property
|
37
|
+
def high_symmetry_points(self) -> tuple[tuple[npt.NDArray[np.float64], str], ...]: # noqa: D102
|
38
|
+
return self._high_symmetry_points
|
quant_met/mean_field/__init__.py
CHANGED
@@ -44,7 +44,9 @@ from .free_energy import (
|
|
44
44
|
free_energy_uniform_pairing,
|
45
45
|
)
|
46
46
|
from .graphene import GrapheneHamiltonian
|
47
|
+
from .one_band_tight_binding import OneBandTightBindingHamiltonian
|
47
48
|
from .quantum_metric import quantum_metric, quantum_metric_bdg
|
49
|
+
from .self_consistency import self_consistency_loop
|
48
50
|
from .superfluid_weight import superfluid_weight
|
49
51
|
|
50
52
|
__all__ = [
|
@@ -55,7 +57,9 @@ __all__ = [
|
|
55
57
|
"free_energy_complex_gap",
|
56
58
|
"free_energy_real_gap",
|
57
59
|
"free_energy_uniform_pairing",
|
60
|
+
"self_consistency_loop",
|
58
61
|
"BaseHamiltonian",
|
59
62
|
"GrapheneHamiltonian",
|
60
63
|
"EGXHamiltonian",
|
64
|
+
"OneBandTightBindingHamiltonian",
|
61
65
|
]
|
@@ -25,9 +25,9 @@ class BaseHamiltonian(ABC):
|
|
25
25
|
raise NotImplementedError
|
26
26
|
|
27
27
|
@property
|
28
|
-
def
|
28
|
+
def hubbard_int_orbital_basis(self) -> npt.NDArray[np.float64]:
|
29
29
|
"""
|
30
|
-
|
30
|
+
hubbard_int interaction split up in orbitals.
|
31
31
|
|
32
32
|
Returns
|
33
33
|
-------
|
@@ -158,7 +158,11 @@ class BaseHamiltonian(ABC):
|
|
158
158
|
|
159
159
|
for i in range(self.number_of_bands):
|
160
160
|
h[:, self.number_of_bands + i, i] = self.delta_orbital_basis[i]
|
161
|
-
h[:, 0:
|
161
|
+
h[:, 0 : self.number_of_bands, self.number_of_bands : self.number_of_bands * 2] = (
|
162
|
+
h[:, self.number_of_bands : self.number_of_bands * 2, 0 : self.number_of_bands]
|
163
|
+
.copy()
|
164
|
+
.conjugate()
|
165
|
+
)
|
162
166
|
|
163
167
|
return h.squeeze()
|
164
168
|
|
@@ -270,6 +274,47 @@ class BaseHamiltonian(ABC):
|
|
270
274
|
|
271
275
|
return bdg_energies.squeeze(), bdg_wavefunctions.squeeze()
|
272
276
|
|
277
|
+
def gap_equation(
|
278
|
+
self, k: npt.NDArray[np.float64], beta: np.float64
|
279
|
+
) -> npt.NDArray[np.complex64]:
|
280
|
+
"""Gap equation.
|
281
|
+
|
282
|
+
Parameters
|
283
|
+
----------
|
284
|
+
beta
|
285
|
+
k
|
286
|
+
|
287
|
+
Returns
|
288
|
+
-------
|
289
|
+
:class:`numpy.ndarray`
|
290
|
+
New gap in orbital basis.
|
291
|
+
|
292
|
+
|
293
|
+
"""
|
294
|
+
bdg_energies, bdg_wavefunctions = self.diagonalize_bdg(k)
|
295
|
+
bdg_energies_minus_k, _ = self.diagonalize_bdg(-k)
|
296
|
+
delta = np.zeros(self.number_of_bands, dtype=np.complex64)
|
297
|
+
|
298
|
+
for i in range(self.number_of_bands):
|
299
|
+
sum_tmp = 0
|
300
|
+
for j in range(self.number_of_bands):
|
301
|
+
for k_index in range(len(k)):
|
302
|
+
sum_tmp += np.conjugate(bdg_wavefunctions[k_index, i, j]) * bdg_wavefunctions[
|
303
|
+
k_index, i + self.number_of_bands, j
|
304
|
+
] * _fermi_dirac(
|
305
|
+
bdg_energies[k_index, j + self.number_of_bands].item(), beta
|
306
|
+
) + np.conjugate(
|
307
|
+
bdg_wavefunctions[k_index, i, j + self.number_of_bands]
|
308
|
+
) * bdg_wavefunctions[
|
309
|
+
k_index, i + self.number_of_bands, j + self.number_of_bands
|
310
|
+
] * _fermi_dirac(
|
311
|
+
-bdg_energies_minus_k[k_index, j + self.number_of_bands].item(), beta
|
312
|
+
)
|
313
|
+
delta[i] = (-self.hubbard_int_orbital_basis[i] * sum_tmp / len(k)).conjugate()
|
314
|
+
|
315
|
+
delta_without_phase: npt.NDArray[np.complex64] = delta * np.exp(-1j * np.angle(delta[0]))
|
316
|
+
return delta_without_phase
|
317
|
+
|
273
318
|
def calculate_bandstructure(
|
274
319
|
self,
|
275
320
|
k: npt.NDArray[np.float64],
|
@@ -298,13 +343,51 @@ class BaseHamiltonian(ABC):
|
|
298
343
|
energies, wavefunctions = self.diagonalize_nonint(k)
|
299
344
|
|
300
345
|
for i, (energy_k, wavefunction_k) in enumerate(zip(energies, wavefunctions, strict=False)):
|
301
|
-
|
302
|
-
results.loc[i,
|
303
|
-
|
304
|
-
|
305
|
-
results.loc[i, f"
|
306
|
-
|
307
|
-
|
308
|
-
|
346
|
+
if self.number_of_bands == 1:
|
347
|
+
results.loc[i, "band"] = energy_k
|
348
|
+
else:
|
349
|
+
for band_index in range(self.number_of_bands):
|
350
|
+
results.loc[i, f"band_{band_index}"] = energy_k[band_index]
|
351
|
+
|
352
|
+
if overlaps is not None:
|
353
|
+
results.loc[i, f"wx_{band_index}"] = (
|
354
|
+
np.abs(np.dot(wavefunction_k[:, band_index], overlaps[0])) ** 2
|
355
|
+
- np.abs(np.dot(wavefunction_k[:, band_index], overlaps[1])) ** 2
|
356
|
+
)
|
309
357
|
|
310
358
|
return results
|
359
|
+
|
360
|
+
def calculate_density_of_states(
|
361
|
+
self, k: npt.NDArray[np.float64], energies: npt.NDArray[np.float64]
|
362
|
+
) -> npt.NDArray[np.float64]:
|
363
|
+
"""Calculate the density of states.
|
364
|
+
|
365
|
+
Parameters
|
366
|
+
----------
|
367
|
+
k
|
368
|
+
energies
|
369
|
+
|
370
|
+
Returns
|
371
|
+
-------
|
372
|
+
Density of states.
|
373
|
+
|
374
|
+
"""
|
375
|
+
density_of_states = np.zeros(shape=energies.shape, dtype=np.float64)
|
376
|
+
bands, _ = self.diagonalize_bdg(k=k)
|
377
|
+
for i, energy in enumerate(energies):
|
378
|
+
density_of_states[i] = np.sum(
|
379
|
+
_gaussian(x=(energy - bands.flatten()), sigma=1e-2)
|
380
|
+
) / len(k)
|
381
|
+
return density_of_states
|
382
|
+
|
383
|
+
|
384
|
+
def _gaussian(x: npt.NDArray[np.float64], sigma: float) -> npt.NDArray[np.float64]:
|
385
|
+
gaussian: npt.NDArray[np.float64] = np.exp(-(x**2) / (2 * sigma**2)) / np.sqrt(
|
386
|
+
2 * np.pi * sigma**2
|
387
|
+
)
|
388
|
+
return gaussian
|
389
|
+
|
390
|
+
|
391
|
+
def _fermi_dirac(energy: np.float64, beta: np.float64) -> np.float64:
|
392
|
+
fermi_dirac: np.float64 = 1 / (1 + np.exp(beta * energy))
|
393
|
+
return fermi_dirac
|
quant_met/mean_field/eg_x.py
CHANGED
@@ -22,9 +22,9 @@ class EGXHamiltonian(BaseHamiltonian):
|
|
22
22
|
hopping_x: float,
|
23
23
|
hopping_x_gr_a: float,
|
24
24
|
lattice_constant: float,
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
chemical_potential: float,
|
26
|
+
hubbard_int_gr: float,
|
27
|
+
hubbard_int_x: float,
|
28
28
|
delta: npt.NDArray[np.complex64] | None = None,
|
29
29
|
*args: tuple[Any, ...],
|
30
30
|
**kwargs: tuple[dict[str, Any], ...],
|
@@ -34,20 +34,28 @@ class EGXHamiltonian(BaseHamiltonian):
|
|
34
34
|
self.hopping_gr = _validate_float(hopping_gr, "Hopping graphene")
|
35
35
|
self.hopping_x = _validate_float(hopping_x, "Hopping impurity")
|
36
36
|
self.hopping_x_gr_a = _validate_float(hopping_x_gr_a, "Hybridisation")
|
37
|
+
if lattice_constant <= 0:
|
38
|
+
msg = "Lattice constant must be positive"
|
39
|
+
raise ValueError(msg)
|
37
40
|
self.lattice_constant = _validate_float(lattice_constant, "Lattice constant")
|
38
|
-
self.
|
39
|
-
self.
|
40
|
-
self.
|
41
|
-
self.
|
41
|
+
self.chemical_potential = _validate_float(chemical_potential, "Chemical potential")
|
42
|
+
self.hubbard_int_gr = _validate_float(hubbard_int_gr, "hubbard_int interaction graphene")
|
43
|
+
self.hubbard_int_x = _validate_float(hubbard_int_x, "hubbard_int interaction impurity")
|
44
|
+
self._hubbard_int_orbital_basis = np.array(
|
45
|
+
[self.hubbard_int_gr, self.hubbard_int_gr, self.hubbard_int_x]
|
46
|
+
)
|
42
47
|
self._number_of_bands = 3
|
43
48
|
if delta is None:
|
44
|
-
self._delta_orbital_basis = np.zeros(
|
49
|
+
self._delta_orbital_basis = np.zeros(self.number_of_bands, dtype=np.complex64)
|
45
50
|
else:
|
46
|
-
|
51
|
+
if delta.shape != (self.number_of_bands,):
|
52
|
+
msg = "Invalid input value for gaps."
|
53
|
+
raise ValueError(msg)
|
54
|
+
self._delta_orbital_basis = np.astype(delta, np.complex64)
|
47
55
|
|
48
56
|
@property
|
49
|
-
def
|
50
|
-
return self.
|
57
|
+
def hubbard_int_orbital_basis(self) -> npt.NDArray[np.float64]: # noqa: D102
|
58
|
+
return self._hubbard_int_orbital_basis
|
51
59
|
|
52
60
|
@property
|
53
61
|
def delta_orbital_basis(self) -> npt.NDArray[np.complex64]: # noqa: D102
|
@@ -82,7 +90,7 @@ class EGXHamiltonian(BaseHamiltonian):
|
|
82
90
|
t_x = self.hopping_x
|
83
91
|
a = self.lattice_constant
|
84
92
|
v = self.hopping_x_gr_a
|
85
|
-
|
93
|
+
chemical_potential = self.chemical_potential
|
86
94
|
if k.ndim == 1:
|
87
95
|
k = np.expand_dims(k, axis=0)
|
88
96
|
|
@@ -106,9 +114,9 @@ class EGXHamiltonian(BaseHamiltonian):
|
|
106
114
|
+ 2 * np.cos(0.5 * a * k[:, 0]) * np.cos(0.5 * np.sqrt(3) * a * k[:, 1])
|
107
115
|
)
|
108
116
|
)
|
109
|
-
h[:, 0, 0] -=
|
110
|
-
h[:, 1, 1] -=
|
111
|
-
h[:, 2, 2] -=
|
117
|
+
h[:, 0, 0] -= chemical_potential
|
118
|
+
h[:, 1, 1] -= chemical_potential
|
119
|
+
h[:, 2, 2] -= chemical_potential
|
112
120
|
|
113
121
|
return h.squeeze()
|
114
122
|
|
@@ -40,7 +40,7 @@ def free_energy(
|
|
40
40
|
)
|
41
41
|
|
42
42
|
integral: float = -np.sum(k_array, axis=-1) / number_k_points + np.sum(
|
43
|
-
np.power(np.abs(hamiltonian.delta_orbital_basis), 2) / hamiltonian.
|
43
|
+
np.power(np.abs(hamiltonian.delta_orbital_basis), 2) / hamiltonian.hubbard_int_orbital_basis
|
44
44
|
)
|
45
45
|
|
46
46
|
return integral
|
quant_met/mean_field/graphene.py
CHANGED
@@ -18,44 +18,47 @@ class GrapheneHamiltonian(BaseHamiltonian):
|
|
18
18
|
|
19
19
|
def __init__(
|
20
20
|
self,
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
hopping: float,
|
22
|
+
lattice_constant: float,
|
23
|
+
chemical_potential: float,
|
24
|
+
hubbard_int_gr: float,
|
25
25
|
delta: npt.NDArray[np.float64] | None = None,
|
26
26
|
*args: tuple[Any, ...],
|
27
27
|
**kwargs: tuple[dict[str, Any], ...],
|
28
28
|
) -> None:
|
29
29
|
del args
|
30
30
|
del kwargs
|
31
|
-
self.
|
32
|
-
if
|
31
|
+
self.hopping = _validate_float(hopping, "Hopping")
|
32
|
+
if lattice_constant <= 0:
|
33
33
|
msg = "Lattice constant must be positive"
|
34
34
|
raise ValueError(msg)
|
35
|
-
self.
|
36
|
-
self.
|
37
|
-
self.
|
38
|
-
self.
|
35
|
+
self.lattice_constant = _validate_float(lattice_constant, "Lattice constant")
|
36
|
+
self.chemical_potential = _validate_float(chemical_potential, "Chemical potential")
|
37
|
+
self.hubbard_int_gr = _validate_float(hubbard_int_gr, "hubbard_int interaction")
|
38
|
+
self._hubbard_int_orbital_basis = np.array([self.hubbard_int_gr, self.hubbard_int_gr])
|
39
39
|
self._number_of_bands = 2
|
40
40
|
if delta is None:
|
41
|
-
self._delta_orbital_basis = np.zeros(
|
41
|
+
self._delta_orbital_basis = np.zeros(self.number_of_bands, dtype=np.complex64)
|
42
42
|
else:
|
43
|
-
|
43
|
+
if delta.shape != (self.number_of_bands,):
|
44
|
+
msg = "Invalid input value for gaps."
|
45
|
+
raise ValueError(msg)
|
46
|
+
self._delta_orbital_basis = np.astype(delta, np.complex64)
|
44
47
|
|
45
48
|
@property
|
46
49
|
def number_of_bands(self) -> int: # noqa: D102
|
47
50
|
return self._number_of_bands
|
48
51
|
|
49
52
|
@property
|
50
|
-
def
|
51
|
-
return self.
|
53
|
+
def hubbard_int_orbital_basis(self) -> npt.NDArray[np.float64]: # noqa: D102
|
54
|
+
return self._hubbard_int_orbital_basis
|
52
55
|
|
53
56
|
@property
|
54
|
-
def delta_orbital_basis(self) -> npt.NDArray[np.
|
57
|
+
def delta_orbital_basis(self) -> npt.NDArray[np.complex64]: # noqa: D102
|
55
58
|
return self._delta_orbital_basis
|
56
59
|
|
57
60
|
@delta_orbital_basis.setter
|
58
|
-
def delta_orbital_basis(self, new_delta: npt.NDArray[np.
|
61
|
+
def delta_orbital_basis(self, new_delta: npt.NDArray[np.complex64]) -> None:
|
59
62
|
self._delta_orbital_basis = new_delta
|
60
63
|
|
61
64
|
def hamiltonian(self, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
|
@@ -74,21 +77,23 @@ class GrapheneHamiltonian(BaseHamiltonian):
|
|
74
77
|
|
75
78
|
"""
|
76
79
|
assert _check_valid_array(k)
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
+
hopping = self.hopping
|
81
|
+
lattice_constant = self.lattice_constant
|
82
|
+
chemical_potential = self.chemical_potential
|
80
83
|
if k.ndim == 1:
|
81
84
|
k = np.expand_dims(k, axis=0)
|
82
85
|
|
83
86
|
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex64)
|
84
87
|
|
85
|
-
h[:, 0, 1] = -
|
86
|
-
np.exp(1j * k[:, 1] *
|
87
|
-
+ 2
|
88
|
+
h[:, 0, 1] = -hopping * (
|
89
|
+
np.exp(1j * k[:, 1] * lattice_constant / np.sqrt(3))
|
90
|
+
+ 2
|
91
|
+
* np.exp(-0.5j * lattice_constant / np.sqrt(3) * k[:, 1])
|
92
|
+
* (np.cos(0.5 * lattice_constant * k[:, 0]))
|
88
93
|
)
|
89
94
|
h[:, 1, 0] = h[:, 0, 1].conjugate()
|
90
|
-
h[:, 0, 0] -=
|
91
|
-
h[:, 1, 1] -=
|
95
|
+
h[:, 0, 0] -= chemical_potential
|
96
|
+
h[:, 1, 1] -= chemical_potential
|
92
97
|
|
93
98
|
return h.squeeze()
|
94
99
|
|
@@ -114,8 +119,8 @@ class GrapheneHamiltonian(BaseHamiltonian):
|
|
114
119
|
assert _check_valid_array(k)
|
115
120
|
assert direction in ["x", "y"]
|
116
121
|
|
117
|
-
|
118
|
-
|
122
|
+
hopping = self.hopping
|
123
|
+
lattice_constant = self.lattice_constant
|
119
124
|
if k.ndim == 1:
|
120
125
|
k = np.expand_dims(k, axis=0)
|
121
126
|
|
@@ -123,18 +128,22 @@ class GrapheneHamiltonian(BaseHamiltonian):
|
|
123
128
|
|
124
129
|
if direction == "x":
|
125
130
|
h[:, 0, 1] = (
|
126
|
-
|
131
|
+
hopping
|
132
|
+
* lattice_constant
|
133
|
+
* np.exp(-0.5j * lattice_constant / np.sqrt(3) * k[:, 1])
|
134
|
+
* np.sin(0.5 * lattice_constant * k[:, 0])
|
127
135
|
)
|
128
136
|
h[:, 1, 0] = h[:, 0, 1].conjugate()
|
129
137
|
else:
|
130
138
|
h[:, 0, 1] = (
|
131
|
-
-
|
139
|
+
-hopping
|
132
140
|
* 1j
|
133
|
-
*
|
141
|
+
* lattice_constant
|
134
142
|
/ np.sqrt(3)
|
135
143
|
* (
|
136
|
-
np.exp(1j *
|
137
|
-
- np.exp(-0.5j *
|
144
|
+
np.exp(1j * lattice_constant / np.sqrt(3) * k[:, 1])
|
145
|
+
- np.exp(-0.5j * lattice_constant / np.sqrt(3) * k[:, 1])
|
146
|
+
* np.cos(0.5 * lattice_constant * k[:, 0])
|
138
147
|
)
|
139
148
|
)
|
140
149
|
h[:, 1, 0] = h[:, 0, 1].conjugate()
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Provides the implementation for Graphene."""
|
6
|
+
|
7
|
+
from typing import Any
|
8
|
+
|
9
|
+
import numpy as np
|
10
|
+
import numpy.typing as npt
|
11
|
+
|
12
|
+
from ._utils import _check_valid_array, _validate_float
|
13
|
+
from .base_hamiltonian import BaseHamiltonian
|
14
|
+
|
15
|
+
|
16
|
+
class OneBandTightBindingHamiltonian(BaseHamiltonian):
|
17
|
+
"""Hamiltonian for Graphene."""
|
18
|
+
|
19
|
+
def __init__(
|
20
|
+
self,
|
21
|
+
hopping: float,
|
22
|
+
lattice_constant: float,
|
23
|
+
chemical_potential: float,
|
24
|
+
hubbard_int: float,
|
25
|
+
delta: npt.NDArray[np.float64] | None = None,
|
26
|
+
*args: tuple[Any, ...],
|
27
|
+
**kwargs: tuple[dict[str, Any], ...],
|
28
|
+
) -> None:
|
29
|
+
del args
|
30
|
+
del kwargs
|
31
|
+
self.hopping = _validate_float(hopping, "Hopping")
|
32
|
+
if lattice_constant <= 0:
|
33
|
+
msg = "Lattice constant must be positive"
|
34
|
+
raise ValueError(msg)
|
35
|
+
self.lattice_constant = _validate_float(lattice_constant, "Lattice constant")
|
36
|
+
self.chemical_potential = _validate_float(chemical_potential, "Chemical potential")
|
37
|
+
self.hubbard_int = _validate_float(hubbard_int, "hubbard_int interaction")
|
38
|
+
self._hubbard_int_orbital_basis = np.array([self.hubbard_int])
|
39
|
+
self._number_of_bands = 1
|
40
|
+
if delta is None:
|
41
|
+
self._delta_orbital_basis = np.zeros(self.number_of_bands, dtype=np.complex64)
|
42
|
+
else:
|
43
|
+
if delta.shape != (self.number_of_bands,):
|
44
|
+
msg = "Invalid input value for gaps."
|
45
|
+
raise ValueError(msg)
|
46
|
+
self._delta_orbital_basis = np.astype(delta, np.complex64)
|
47
|
+
|
48
|
+
@property
|
49
|
+
def number_of_bands(self) -> int: # noqa: D102
|
50
|
+
return self._number_of_bands
|
51
|
+
|
52
|
+
@property
|
53
|
+
def hubbard_int_orbital_basis(self) -> npt.NDArray[np.float64]: # noqa: D102
|
54
|
+
return self._hubbard_int_orbital_basis
|
55
|
+
|
56
|
+
@property
|
57
|
+
def delta_orbital_basis(self) -> npt.NDArray[np.complex64]: # noqa: D102
|
58
|
+
return self._delta_orbital_basis
|
59
|
+
|
60
|
+
@delta_orbital_basis.setter
|
61
|
+
def delta_orbital_basis(self, new_delta: npt.NDArray[np.complex64]) -> None:
|
62
|
+
self._delta_orbital_basis = new_delta
|
63
|
+
|
64
|
+
def hamiltonian(self, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
|
65
|
+
"""
|
66
|
+
Return the normal state Hamiltonian in orbital basis.
|
67
|
+
|
68
|
+
Parameters
|
69
|
+
----------
|
70
|
+
k : :class:`numpy.ndarray`
|
71
|
+
List of k points.
|
72
|
+
|
73
|
+
Returns
|
74
|
+
-------
|
75
|
+
:class:`numpy.ndarray`
|
76
|
+
Hamiltonian in matrix form.
|
77
|
+
|
78
|
+
"""
|
79
|
+
assert _check_valid_array(k)
|
80
|
+
hopping = self.hopping
|
81
|
+
lattice_constant = self.lattice_constant
|
82
|
+
chemical_potential = self.chemical_potential
|
83
|
+
if k.ndim == 1:
|
84
|
+
k = np.expand_dims(k, axis=0)
|
85
|
+
|
86
|
+
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex64)
|
87
|
+
|
88
|
+
h[:, 0, 0] = (
|
89
|
+
-2 * hopping * (np.cos(k[:, 1] * lattice_constant) + np.cos(k[:, 0] * lattice_constant))
|
90
|
+
)
|
91
|
+
h[:, 0, 0] -= chemical_potential
|
92
|
+
|
93
|
+
return h
|
94
|
+
|
95
|
+
def hamiltonian_derivative(
|
96
|
+
self, k: npt.NDArray[np.float64], direction: str
|
97
|
+
) -> npt.NDArray[np.complex64]:
|
98
|
+
"""
|
99
|
+
Deriative of the Hamiltonian.
|
100
|
+
|
101
|
+
Parameters
|
102
|
+
----------
|
103
|
+
k: :class:`numpy.ndarray`
|
104
|
+
List of k points.
|
105
|
+
direction: str
|
106
|
+
Direction for derivative, either 'x' oder 'y'.
|
107
|
+
|
108
|
+
Returns
|
109
|
+
-------
|
110
|
+
:class:`numpy.ndarray`
|
111
|
+
Derivative of Hamiltonian.
|
112
|
+
|
113
|
+
"""
|
114
|
+
assert _check_valid_array(k)
|
115
|
+
assert direction in ["x", "y"]
|
116
|
+
|
117
|
+
hopping = self.hopping
|
118
|
+
lattice_constant = self.lattice_constant
|
119
|
+
if k.ndim == 1:
|
120
|
+
k = np.expand_dims(k, axis=0)
|
121
|
+
|
122
|
+
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex64)
|
123
|
+
|
124
|
+
if direction == "x":
|
125
|
+
h[:, 0, 0] = -2 * hopping * lattice_constant * np.sin(lattice_constant * k[:, 0])
|
126
|
+
else:
|
127
|
+
h[:, 0, 0] = -2 * hopping * lattice_constant * np.sin(lattice_constant * k[:, 0])
|
128
|
+
|
129
|
+
return h.squeeze()
|
@@ -11,18 +11,17 @@ from .base_hamiltonian import BaseHamiltonian
|
|
11
11
|
|
12
12
|
|
13
13
|
def quantum_metric(
|
14
|
-
h: BaseHamiltonian, k_grid: npt.NDArray[np.float64],
|
14
|
+
h: BaseHamiltonian, k_grid: npt.NDArray[np.float64], bands: list[int]
|
15
15
|
) -> npt.NDArray[np.float64]:
|
16
16
|
"""Calculate the quantum metric in the normal state.
|
17
17
|
|
18
18
|
Parameters
|
19
19
|
----------
|
20
|
+
bands
|
20
21
|
h : :class:`~quant_met.BaseHamiltonian`
|
21
22
|
Hamiltonian object.
|
22
23
|
k_grid : :class:`numpy.ndarray`
|
23
24
|
List of k points.
|
24
|
-
band : int
|
25
|
-
Index of band for which the quantum metric is calculated.
|
26
25
|
|
27
26
|
Returns
|
28
27
|
-------
|
@@ -36,25 +35,26 @@ def quantum_metric(
|
|
36
35
|
|
37
36
|
quantum_geom_tensor = np.zeros(shape=(2, 2), dtype=np.complex64)
|
38
37
|
|
39
|
-
for
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
for
|
45
|
-
|
46
|
-
(
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
38
|
+
for band in bands:
|
39
|
+
for i, direction_1 in enumerate(["x", "y"]):
|
40
|
+
h_derivative_direction_1 = h.hamiltonian_derivative(k=k_grid, direction=direction_1)
|
41
|
+
for j, direction_2 in enumerate(["x", "y"]):
|
42
|
+
h_derivative_direction_2 = h.hamiltonian_derivative(k=k_grid, direction=direction_2)
|
43
|
+
for k_index in range(len(k_grid)):
|
44
|
+
for n in [i for i in range(h.number_of_bands) if i != band]:
|
45
|
+
quantum_geom_tensor[i, j] += (
|
46
|
+
(
|
47
|
+
bloch[k_index][:, band].conjugate()
|
48
|
+
@ h_derivative_direction_1[k_index]
|
49
|
+
@ bloch[k_index][:, n]
|
50
|
+
)
|
51
|
+
* (
|
52
|
+
bloch[k_index][:, n].conjugate()
|
53
|
+
@ h_derivative_direction_2[k_index]
|
54
|
+
@ bloch[k_index][:, band]
|
55
|
+
)
|
56
|
+
/ (energies[k_index][band] - energies[k_index][n]) ** 2
|
55
57
|
)
|
56
|
-
/ (energies[k_index][band] - energies[k_index][n]) ** 2
|
57
|
-
)
|
58
58
|
|
59
59
|
return np.real(quantum_geom_tensor) / number_k_points
|
60
60
|
|
@@ -66,12 +66,11 @@ def quantum_metric_bdg(
|
|
66
66
|
|
67
67
|
Parameters
|
68
68
|
----------
|
69
|
+
bands
|
69
70
|
h : :class:`~quant_met.BaseHamiltonian`
|
70
71
|
Hamiltonian object.
|
71
72
|
k_grid : :class:`numpy.ndarray`
|
72
73
|
List of k points.
|
73
|
-
band : int
|
74
|
-
Index of band for which the quantum metric is calculated.
|
75
74
|
|
76
75
|
Returns
|
77
76
|
-------
|
@@ -91,7 +90,7 @@ def quantum_metric_bdg(
|
|
91
90
|
for j, direction_2 in enumerate(["x", "y"]):
|
92
91
|
h_derivative_dir_2 = h.bdg_hamiltonian_derivative(k=k_grid, direction=direction_2)
|
93
92
|
for k_index in range(len(k_grid)):
|
94
|
-
for n in [i for i in range(h.number_of_bands) if i != band]:
|
93
|
+
for n in [i for i in range(2 * h.number_of_bands) if i != band]:
|
95
94
|
quantum_geom_tensor[i, j] += (
|
96
95
|
(
|
97
96
|
bdg_functions[k_index][:, band].conjugate()
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Self-consistency loop."""
|
6
|
+
|
7
|
+
import numpy as np
|
8
|
+
|
9
|
+
from quant_met import geometry
|
10
|
+
|
11
|
+
from .base_hamiltonian import BaseHamiltonian
|
12
|
+
|
13
|
+
|
14
|
+
def self_consistency_loop(
|
15
|
+
h: BaseHamiltonian, beta: np.float64, number_of_k_points: int, epsilon: float
|
16
|
+
) -> BaseHamiltonian:
|
17
|
+
"""Self-consistency loop.
|
18
|
+
|
19
|
+
Parameters
|
20
|
+
----------
|
21
|
+
beta
|
22
|
+
number_of_k_points
|
23
|
+
h
|
24
|
+
epsilon
|
25
|
+
"""
|
26
|
+
lattice = geometry.Graphene(lattice_constant=np.sqrt(3))
|
27
|
+
k_space_grid = lattice.generate_bz_grid(ncols=number_of_k_points, nrows=number_of_k_points)
|
28
|
+
rng = np.random.default_rng()
|
29
|
+
delta_init = np.zeros(shape=h.delta_orbital_basis.shape, dtype=np.float64)
|
30
|
+
rng.random(size=h.delta_orbital_basis.shape, out=delta_init)
|
31
|
+
h.delta_orbital_basis = delta_init.astype(np.complex64)
|
32
|
+
|
33
|
+
while True:
|
34
|
+
new_gap = h.gap_equation(k=k_space_grid, beta=beta)
|
35
|
+
if (np.abs(h.delta_orbital_basis - new_gap) < epsilon).all():
|
36
|
+
h.delta_orbital_basis = new_gap
|
37
|
+
return h
|
38
|
+
mixing_greed = 0.2
|
39
|
+
h.delta_orbital_basis = mixing_greed * new_gap + (1 - mixing_greed) * h.delta_orbital_basis
|
quant_met/plotting/__init__.py
CHANGED
@@ -14,15 +14,25 @@ Functions
|
|
14
14
|
.. autosummary::
|
15
15
|
:toctree: generated/
|
16
16
|
|
17
|
+
format_plot
|
17
18
|
scatter_into_bz
|
18
19
|
plot_bandstructure
|
19
|
-
|
20
|
+
plot_superfluid_weight
|
21
|
+
plot_quantum_metric
|
20
22
|
""" # noqa: D205, D400
|
21
23
|
|
22
|
-
from .plotting import
|
24
|
+
from .plotting import (
|
25
|
+
format_plot,
|
26
|
+
plot_bandstructure,
|
27
|
+
plot_quantum_metric,
|
28
|
+
plot_superfluid_weight,
|
29
|
+
scatter_into_bz,
|
30
|
+
)
|
23
31
|
|
24
32
|
__all__ = [
|
25
33
|
"scatter_into_bz",
|
34
|
+
"format_plot",
|
26
35
|
"plot_bandstructure",
|
27
|
-
"
|
36
|
+
"plot_superfluid_weight",
|
37
|
+
"plot_quantum_metric",
|
28
38
|
]
|
quant_met/plotting/plotting.py
CHANGED
@@ -4,8 +4,6 @@
|
|
4
4
|
|
5
5
|
"""Methods for plotting data."""
|
6
6
|
|
7
|
-
from typing import Any
|
8
|
-
|
9
7
|
import matplotlib.axes
|
10
8
|
import matplotlib.colors
|
11
9
|
import matplotlib.figure
|
@@ -13,7 +11,28 @@ import matplotlib.pyplot as plt
|
|
13
11
|
import numpy as np
|
14
12
|
import numpy.typing as npt
|
15
13
|
from matplotlib.collections import Collection, LineCollection
|
16
|
-
|
14
|
+
|
15
|
+
|
16
|
+
def format_plot(
|
17
|
+
ax: matplotlib.axes.Axes,
|
18
|
+
) -> matplotlib.axes.Axes:
|
19
|
+
"""Format the axis to the predefined style.
|
20
|
+
|
21
|
+
Parameters
|
22
|
+
----------
|
23
|
+
ax : :class:`matplotlib.axes.Axes`
|
24
|
+
|
25
|
+
Returns
|
26
|
+
-------
|
27
|
+
:class:`matplotlib.axes.Axes`
|
28
|
+
|
29
|
+
"""
|
30
|
+
ax.set_box_aspect(1)
|
31
|
+
ax.set_facecolor("lightgray")
|
32
|
+
ax.grid(visible=True)
|
33
|
+
ax.tick_params(axis="both", direction="in", bottom=True, top=True, left=True, right=True)
|
34
|
+
|
35
|
+
return ax
|
17
36
|
|
18
37
|
|
19
38
|
def scatter_into_bz(
|
@@ -107,7 +126,6 @@ def plot_bandstructure(
|
|
107
126
|
:obj:`matplotlib.figure.Figure`
|
108
127
|
Figure with the data plotted onto the axis.
|
109
128
|
|
110
|
-
|
111
129
|
"""
|
112
130
|
if fig_in is None or ax_in is None:
|
113
131
|
fig, ax = plt.subplots()
|
@@ -139,92 +157,92 @@ def plot_bandstructure(
|
|
139
157
|
top=float(np.max(bands) + 0.1 * np.max(bands)),
|
140
158
|
bottom=float(np.min(bands) - 0.1 * np.abs(np.min(bands))),
|
141
159
|
)
|
142
|
-
ax.set_box_aspect(1)
|
143
160
|
ax.set_xticks(ticks, labels)
|
161
|
+
|
162
|
+
ax = format_plot(ax)
|
163
|
+
|
144
164
|
ax.set_ylabel(r"$E\ [t]$")
|
145
|
-
ax.set_facecolor("lightgray")
|
146
|
-
ax.grid(visible=True)
|
147
|
-
ax.tick_params(axis="both", direction="in", bottom=True, top=True, left=True, right=True)
|
148
165
|
|
149
166
|
return fig
|
150
167
|
|
151
168
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
return np.vstack(
|
162
|
-
[
|
163
|
-
np.linspace(p_0[0], p_1[0], number_of_points),
|
164
|
-
np.linspace(p_0[1], p_1[1], number_of_points),
|
165
|
-
]
|
166
|
-
).T[:-1]
|
167
|
-
|
168
|
-
|
169
|
-
def generate_bz_path(
|
170
|
-
points: list[tuple[npt.NDArray[np.float64], str]], number_of_points: int = 1000
|
171
|
-
) -> tuple[
|
172
|
-
ndarray[Any, dtype[generic | Any]],
|
173
|
-
ndarray[Any, dtype[generic | Any]],
|
174
|
-
list[int | Any],
|
175
|
-
list[str],
|
176
|
-
]:
|
177
|
-
"""Generate a path through high symmetry points.
|
169
|
+
def plot_superfluid_weight(
|
170
|
+
x_data: npt.NDArray[np.float64],
|
171
|
+
sf_weight_geom: npt.NDArray[np.float64],
|
172
|
+
sf_weight_conv: npt.NDArray[np.float64],
|
173
|
+
fig_in: matplotlib.figure.Figure | None = None,
|
174
|
+
ax_in: matplotlib.axes.Axes | None = None,
|
175
|
+
) -> matplotlib.figure.Figure:
|
176
|
+
"""Plot superfluid weight against some parameter.
|
178
177
|
|
179
178
|
Parameters
|
180
179
|
----------
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
180
|
+
x_data : :class:`numpy.ndarray`
|
181
|
+
sf_weight_geom : :class:`numpy.ndarray`
|
182
|
+
sf_weight_conv : :class:`numpy.ndarray`
|
183
|
+
fig_in : :class:`matplotlib.figure.Figure`, optional
|
184
|
+
ax_in : :class:`matplotlib.axes.Axes`, optional
|
185
185
|
|
186
186
|
Returns
|
187
187
|
-------
|
188
|
-
:
|
189
|
-
|
190
|
-
:class:`numpy.ndarray`
|
191
|
-
Path for plotting purposes: points between 0 and 1, with appropiate spacing.
|
192
|
-
list[float]
|
193
|
-
A list of ticks for the plotting path.
|
194
|
-
list[str]
|
195
|
-
A list of labels for the plotting path.
|
188
|
+
:obj:`matplotlib.figure.Figure`
|
189
|
+
Figure with the data plotted onto the axis.
|
196
190
|
|
197
191
|
"""
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
ticks = [0]
|
206
|
-
ticks.extend([np.sum(cycle[0 : i + 1]) / length_whole_path for i in range(len(cycle) - 1)])
|
207
|
-
ticks.append(1)
|
208
|
-
labels = [rf"${points[i][1]}$" for i in range(len(points))]
|
209
|
-
labels.append(rf"${points[0][1]}$")
|
210
|
-
|
211
|
-
whole_path_plot = np.concatenate(
|
212
|
-
[
|
213
|
-
np.linspace(
|
214
|
-
ticks[i],
|
215
|
-
ticks[i + 1],
|
216
|
-
num=int(n * cycle[i] / length_whole_path),
|
217
|
-
endpoint=False,
|
218
|
-
)
|
219
|
-
for i in range(len(ticks) - 1)
|
220
|
-
]
|
192
|
+
if fig_in is None or ax_in is None:
|
193
|
+
fig, ax = plt.subplots()
|
194
|
+
else:
|
195
|
+
fig, ax = fig_in, ax_in
|
196
|
+
|
197
|
+
ax.fill_between(
|
198
|
+
x_data, 0, np.abs(sf_weight_geom), color="black", fc="#0271BB", label="geometric", hatch="-"
|
221
199
|
)
|
200
|
+
ax.fill_between(
|
201
|
+
x_data,
|
202
|
+
np.abs(sf_weight_geom),
|
203
|
+
np.abs(sf_weight_geom) + np.abs(sf_weight_conv),
|
204
|
+
color="black",
|
205
|
+
fc="#E2001A",
|
206
|
+
label="conventional",
|
207
|
+
hatch="//",
|
208
|
+
)
|
209
|
+
ax.plot(x_data, np.abs(sf_weight_geom) + np.abs(sf_weight_conv), "x--", color="black")
|
210
|
+
|
211
|
+
ax = format_plot(ax)
|
212
|
+
ax.set_ylabel(r"$D_S\ [t]$")
|
213
|
+
|
214
|
+
return fig
|
222
215
|
|
223
|
-
points_path = [
|
224
|
-
_generate_part_of_path(points[i][0], points[i + 1][0], n, length_whole_path)
|
225
|
-
for i in range(len(points) - 1)
|
226
|
-
]
|
227
|
-
points_path.append(_generate_part_of_path(points[-1][0], points[0][0], n, length_whole_path))
|
228
|
-
whole_path = np.concatenate(points_path)
|
229
216
|
|
230
|
-
|
217
|
+
def plot_quantum_metric(
|
218
|
+
x_data: npt.NDArray[np.float64],
|
219
|
+
quantum_metric: npt.NDArray[np.float64],
|
220
|
+
fig_in: matplotlib.figure.Figure | None = None,
|
221
|
+
ax_in: matplotlib.axes.Axes | None = None,
|
222
|
+
) -> matplotlib.figure.Figure:
|
223
|
+
"""Plot quantum metric against some parameter.
|
224
|
+
|
225
|
+
Parameters
|
226
|
+
----------
|
227
|
+
x_data : :class:`numpy.ndarray`
|
228
|
+
quantum_metric : :class:`numpy.ndarray`
|
229
|
+
fig_in : :class:`matplotlib.figure.Figure`, optional
|
230
|
+
ax_in : :class:`matplotlib.axes.Axes`, optional
|
231
|
+
|
232
|
+
Returns
|
233
|
+
-------
|
234
|
+
:obj:`matplotlib.figure.Figure`
|
235
|
+
Figure with the data plotted onto the axis.
|
236
|
+
|
237
|
+
"""
|
238
|
+
if fig_in is None or ax_in is None:
|
239
|
+
fig, ax = plt.subplots()
|
240
|
+
else:
|
241
|
+
fig, ax = fig_in, ax_in
|
242
|
+
|
243
|
+
ax.plot(x_data, quantum_metric, "x--")
|
244
|
+
|
245
|
+
ax = format_plot(ax)
|
246
|
+
ax.set_ylabel(r"$M\ [t]$")
|
247
|
+
|
248
|
+
return fig
|
@@ -1,18 +1,21 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: quant-met
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.7
|
4
4
|
Summary: Calculate superconductivity in flat-band systems.
|
5
|
+
Home-page: https://quant-met.tjarksievers.de
|
5
6
|
Author: Tjark Sievers
|
6
7
|
Author-email: tsievers@physnet.uni-hamburg.de
|
7
8
|
Requires-Python: >=3.11,<4.0
|
8
9
|
Classifier: Programming Language :: Python :: 3
|
9
10
|
Classifier: Programming Language :: Python :: 3.11
|
10
11
|
Classifier: Programming Language :: Python :: 3.12
|
11
|
-
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
13
|
+
Requires-Dist: h5py (>=3.12.1,<4.0.0)
|
12
14
|
Requires-Dist: matplotlib (>=3.9.2,<4.0.0)
|
13
|
-
Requires-Dist: numpy (>=2.
|
14
|
-
Requires-Dist: pandas (>=2.2.
|
15
|
-
Requires-Dist: scipy (>=1.14.
|
15
|
+
Requires-Dist: numpy (>=2.1.2,<3.0.0)
|
16
|
+
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
17
|
+
Requires-Dist: scipy (>=1.14.1,<2.0.0)
|
18
|
+
Project-URL: Repository, https://github.com/Ruberhauptmann/quant-met
|
16
19
|
Description-Content-Type: text/markdown
|
17
20
|
|
18
21
|
<!--
|
@@ -30,7 +33,7 @@ SPDX-License-Identifier: MIT
|
|
30
33
|
|
31
34
|
This is a python package to treat superconductivity in flat-band systems.
|
32
35
|
|
33
|
-
* Documentation: [quant-met.
|
36
|
+
* Documentation: [quant-met.tjarksievers.de](https://quant-met.tjarksievers.de)
|
34
37
|
|
35
38
|
## Installation
|
36
39
|
|
@@ -41,7 +44,7 @@ pip install quant-met
|
|
41
44
|
|
42
45
|
## Usage
|
43
46
|
|
44
|
-
For usage examples see [documentation](https://quant-met.
|
47
|
+
For usage examples see [documentation](https://quant-met.tjarksievers.de/en/latest/examples.html).
|
45
48
|
|
46
49
|
## Contributing
|
47
50
|
|
@@ -69,5 +72,10 @@ After pushing your branch, all tests will also be run via Github Actions.
|
|
69
72
|
Using `pre-commit`, automatic linting and formatting is done before every commit, which may cause the first commit to fail.
|
70
73
|
A second try should then succeed.
|
71
74
|
|
75
|
+
To fix the reuse copyright:
|
76
|
+
```bash
|
77
|
+
reuse annotate --license=MIT --copyright="Tjark Sievers" --skip-unrecognised -r .
|
78
|
+
```
|
79
|
+
|
72
80
|
After you are done working on an issue and all tests are running successful, you can add a new piece of changelog via `scriv create` and make a pull request.
|
73
81
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
quant_met/__init__.py,sha256=ZO1UFz1awUYTI7B9ZkBwucvDz7GMGXnLLUGnEwLBhkc,155
|
2
|
+
quant_met/geometry/__init__.py,sha256=dWT4yYDBKsJUI9Hv1DDCGtqx-lDLQF6mH7xSRLomvD4,508
|
3
|
+
quant_met/geometry/base_lattice.py,sha256=QVHuZVy6bOvBSITY_mKhr7hYW1jHJ5UAm3sMCFClYZ0,2276
|
4
|
+
quant_met/geometry/bz_path.py,sha256=q_eNhKYjhKLeFNjio8BdKVsseO6slQKlwKKSQQYTVJQ,2497
|
5
|
+
quant_met/geometry/graphene.py,sha256=37CZXj_NpFsnR1pPE_jFbrAiiMFhs1Q3FLlcgqG2pwM,1264
|
6
|
+
quant_met/geometry/square.py,sha256=1fSrHab07uB6ildNzlbTwINJvPa5C2Az0B0uuOVJmMc,1216
|
7
|
+
quant_met/mean_field/__init__.py,sha256=sXKp572huLdcqYEj0b9ojgefLiOiIHV7CH2XN54WU7E,1368
|
8
|
+
quant_met/mean_field/_utils.py,sha256=plkx6eYjyYV3CT3BWwlulqW7L-Q0t1TzZTLR4k7u0dg,666
|
9
|
+
quant_met/mean_field/base_hamiltonian.py,sha256=kUZ6-eU525l_9e3YoSA66HsE9c5isUNjNqOh6T71OGk,11773
|
10
|
+
quant_met/mean_field/eg_x.py,sha256=w-6UcSVYPC-B58152aJpp0HDNoxyy46c6eXNZCGHi6Q,5805
|
11
|
+
quant_met/mean_field/free_energy.py,sha256=59GPLJhyllyAJEZteAr6iYqCbHGFsmV1zcYxJ8Aw9Ao,3448
|
12
|
+
quant_met/mean_field/graphene.py,sha256=8xMR43ndL5oJ7BbYBVGxWTLU5BscsE8ixTpPlCZzKO8,4917
|
13
|
+
quant_met/mean_field/one_band_tight_binding.py,sha256=ZfZQZxcqoKRtx3oomQyXwuong81K5vKKg0cyjs5JJ48,4138
|
14
|
+
quant_met/mean_field/quantum_metric.py,sha256=3OiwSDxz_Pw4uioGO18lYyYb_myK2kSCwF9AloUZIt4,3870
|
15
|
+
quant_met/mean_field/self_consistency.py,sha256=r2J9mEEcgWkI92exEol0tkwoWlM9ithodgNzdKEQpfs,1193
|
16
|
+
quant_met/mean_field/superfluid_weight.py,sha256=840Fe3aHOVz1W7hi5GrX69_QxQ3vmdy3H0_B852dZqA,3971
|
17
|
+
quant_met/plotting/__init__.py,sha256=s-DS22impzozKiS7p-v3yCmeccDQfXmBbtPiYMKwH0Y,620
|
18
|
+
quant_met/plotting/plotting.py,sha256=_SqL8GrDqlBtccHnUWpZPqdSJy0Yd_4dhFdUOxOzPpY,7447
|
19
|
+
quant_met/utils.py,sha256=Tvw_YfqjIWx0FPGSReikSnw9xfN-T2dpQZN-KPMa69A,1709
|
20
|
+
quant_met-0.0.7.dist-info/LICENSE.txt,sha256=QO_duPQihSJlaxSLxPAXo52X3esROP5wBkhxqBd1Z4E,1104
|
21
|
+
quant_met-0.0.7.dist-info/LICENSES/MIT.txt,sha256=QO_duPQihSJlaxSLxPAXo52X3esROP5wBkhxqBd1Z4E,1104
|
22
|
+
quant_met-0.0.7.dist-info/METADATA,sha256=eq-LGEGvKZsMw_MC5guVaJvrfvF24OmMkNLj6l74CRo,2880
|
23
|
+
quant_met-0.0.7.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
24
|
+
quant_met-0.0.7.dist-info/RECORD,,
|
quant_met-0.0.5.dist-info/RECORD
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
quant_met/__init__.py,sha256=ZO1UFz1awUYTI7B9ZkBwucvDz7GMGXnLLUGnEwLBhkc,155
|
2
|
-
quant_met/mean_field/__init__.py,sha256=msHp5Y5cuHjqr_EdC9jS9JKpeAi6CBHggtxrG_psDRk,1182
|
3
|
-
quant_met/mean_field/_utils.py,sha256=plkx6eYjyYV3CT3BWwlulqW7L-Q0t1TzZTLR4k7u0dg,666
|
4
|
-
quant_met/mean_field/base_hamiltonian.py,sha256=7rNBbkoSSaIQVg4GiKDI1WaSZxJiGR26bdidh9uygzw,8812
|
5
|
-
quant_met/mean_field/eg_x.py,sha256=y_DWBoyRaHVIof_itAgHaoaFEEssY_Q9mhvsKC7DxdM,5286
|
6
|
-
quant_met/mean_field/free_energy.py,sha256=FSGCHoBO1myHGwGQ8CqGu7_08whH0Ot3ikZhBu27tyM,3444
|
7
|
-
quant_met/mean_field/graphene.py,sha256=rKD2UjB0blN4ALePk4bQlg0XahHoe_3mCqRAvEUGiqI,4162
|
8
|
-
quant_met/mean_field/quantum_metric.py,sha256=y-ky4bU566TNBxldaYWyloqojfpTODo9gbn4TPe6-4A,3902
|
9
|
-
quant_met/mean_field/superfluid_weight.py,sha256=840Fe3aHOVz1W7hi5GrX69_QxQ3vmdy3H0_B852dZqA,3971
|
10
|
-
quant_met/plotting/__init__.py,sha256=QRQ3TNb0PNQi2lWXY0LHKgYSRuegM1N3dVVs9146Zug,457
|
11
|
-
quant_met/plotting/plotting.py,sha256=iVTFZ9tQz_GalzqbQhxCiNWOhYHJM4wiZPTjXaXnApM,7326
|
12
|
-
quant_met/utils.py,sha256=Tvw_YfqjIWx0FPGSReikSnw9xfN-T2dpQZN-KPMa69A,1709
|
13
|
-
quant_met-0.0.5.dist-info/LICENSE.txt,sha256=QO_duPQihSJlaxSLxPAXo52X3esROP5wBkhxqBd1Z4E,1104
|
14
|
-
quant_met-0.0.5.dist-info/LICENSES/MIT.txt,sha256=QO_duPQihSJlaxSLxPAXo52X3esROP5wBkhxqBd1Z4E,1104
|
15
|
-
quant_met-0.0.5.dist-info/METADATA,sha256=Kh99UUBpu1y3cOU1wYektey2RuA1a5Xd_acXxMQnsyc,2598
|
16
|
-
quant_met-0.0.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
17
|
-
quant_met-0.0.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|