quant-met 0.0.2__py3-none-any.whl → 0.0.3__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/__init__.py +2 -4
- quant_met/mean_field/__init__.py +60 -0
- quant_met/mean_field/_utils.py +27 -0
- quant_met/{hamiltonians/_base_hamiltonian.py → mean_field/base_hamiltonian.py} +151 -27
- quant_met/mean_field/eg_x.py +120 -0
- quant_met/mean_field/free_energy.py +130 -0
- quant_met/{hamiltonians/_graphene.py → mean_field/graphene.py} +26 -22
- quant_met/mean_field/quantum_metric.py +59 -0
- quant_met/{hamiltonians/_superfluid_weight.py → mean_field/superfluid_weight.py} +66 -50
- quant_met/plotting/__init__.py +22 -1
- quant_met/plotting/plotting.py +230 -0
- quant_met/utils.py +45 -2
- quant_met-0.0.3.dist-info/LICENSES/MIT.txt +9 -0
- {quant_met-0.0.2.dist-info → quant_met-0.0.3.dist-info}/METADATA +11 -7
- quant_met-0.0.3.dist-info/RECORD +17 -0
- quant_met/hamiltonians/__init__.py +0 -14
- quant_met/hamiltonians/_eg_x.py +0 -124
- quant_met/hamiltonians/_free_energy.py +0 -39
- quant_met/hamiltonians/_utils.py +0 -10
- quant_met/plotting/_plotting.py +0 -156
- quant_met-0.0.2.dist-info/RECORD +0 -15
- {quant_met-0.0.2.dist-info → quant_met-0.0.3.dist-info}/LICENSE.txt +0 -0
- {quant_met-0.0.2.dist-info → quant_met-0.0.3.dist-info}/WHEEL +0 -0
@@ -1,11 +1,19 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Provides the implementation for Graphene."""
|
6
|
+
|
1
7
|
import numpy as np
|
2
8
|
import numpy.typing as npt
|
3
9
|
|
4
|
-
from .
|
5
|
-
from .
|
10
|
+
from ._utils import _validate_float
|
11
|
+
from .base_hamiltonian import BaseHamiltonian
|
6
12
|
|
7
13
|
|
8
14
|
class GrapheneHamiltonian(BaseHamiltonian):
|
15
|
+
"""Hamiltonian for Graphene."""
|
16
|
+
|
9
17
|
def __init__(
|
10
18
|
self,
|
11
19
|
t_nn: float,
|
@@ -13,28 +21,31 @@ class GrapheneHamiltonian(BaseHamiltonian):
|
|
13
21
|
mu: float,
|
14
22
|
coulomb_gr: float,
|
15
23
|
delta: npt.NDArray[np.float64] | None = None,
|
16
|
-
):
|
17
|
-
self.t_nn =
|
24
|
+
) -> None:
|
25
|
+
self.t_nn = _validate_float(t_nn, "Hopping")
|
18
26
|
if a <= 0:
|
19
|
-
|
20
|
-
|
21
|
-
self.
|
22
|
-
self.
|
27
|
+
msg = "Lattice constant must be positive"
|
28
|
+
raise ValueError(msg)
|
29
|
+
self.a = _validate_float(a, "Lattice constant")
|
30
|
+
self.mu = _validate_float(mu, "Chemical potential")
|
31
|
+
self.coulomb_gr = _validate_float(coulomb_gr, "Coloumb interaction")
|
32
|
+
self._coloumb_orbital_basis = np.array([self.coulomb_gr, self.coulomb_gr])
|
33
|
+
self._number_of_bands = 2
|
23
34
|
if delta is None:
|
24
35
|
self._delta_orbital_basis = np.zeros(2)
|
25
36
|
else:
|
26
37
|
self._delta_orbital_basis = delta
|
27
38
|
|
28
39
|
@property
|
29
|
-
def
|
30
|
-
return
|
40
|
+
def number_of_bands(self) -> int: # noqa: D102
|
41
|
+
return self._number_of_bands
|
31
42
|
|
32
43
|
@property
|
33
|
-
def
|
34
|
-
return
|
44
|
+
def coloumb_orbital_basis(self) -> npt.NDArray[np.float64]: # noqa: D102
|
45
|
+
return self._coloumb_orbital_basis
|
35
46
|
|
36
47
|
@property
|
37
|
-
def delta_orbital_basis(self) -> npt.NDArray[np.float64]:
|
48
|
+
def delta_orbital_basis(self) -> npt.NDArray[np.float64]: # noqa: D102
|
38
49
|
return self._delta_orbital_basis
|
39
50
|
|
40
51
|
@delta_orbital_basis.setter
|
@@ -52,12 +63,7 @@ class GrapheneHamiltonian(BaseHamiltonian):
|
|
52
63
|
h = np.zeros((self.number_of_bands, self.number_of_bands), dtype=np.complex64)
|
53
64
|
|
54
65
|
if direction == "x":
|
55
|
-
h[0, 1] = (
|
56
|
-
t_nn
|
57
|
-
* a
|
58
|
-
* np.exp(-0.5j * a / np.sqrt(3) * k[1])
|
59
|
-
* np.sin(0.5 * a * k[0])
|
60
|
-
)
|
66
|
+
h[0, 1] = t_nn * a * np.exp(-0.5j * a / np.sqrt(3) * k[1]) * np.sin(0.5 * a * k[0])
|
61
67
|
h[1, 0] = h[0, 1].conjugate()
|
62
68
|
else:
|
63
69
|
h[0, 1] = (
|
@@ -74,9 +80,7 @@ class GrapheneHamiltonian(BaseHamiltonian):
|
|
74
80
|
|
75
81
|
return h
|
76
82
|
|
77
|
-
def _hamiltonian_one_point(
|
78
|
-
self, k: npt.NDArray[np.float64]
|
79
|
-
) -> npt.NDArray[np.complex64]:
|
83
|
+
def _hamiltonian_one_point(self, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
|
80
84
|
t_nn = self.t_nn
|
81
85
|
a = self.a
|
82
86
|
mu = self.mu
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Functions to calculate the quantum metric."""
|
6
|
+
|
7
|
+
import numpy as np
|
8
|
+
import numpy.typing as npt
|
9
|
+
|
10
|
+
from .base_hamiltonian import BaseHamiltonian
|
11
|
+
|
12
|
+
|
13
|
+
def quantum_metric(
|
14
|
+
h: BaseHamiltonian, k_grid: npt.NDArray[np.float64], band: int
|
15
|
+
) -> npt.NDArray[np.float64]:
|
16
|
+
"""Calculate the quantum metric in the normal state.
|
17
|
+
|
18
|
+
Parameters
|
19
|
+
----------
|
20
|
+
h : :class:`~quant_met.BaseHamiltonian`
|
21
|
+
Hamiltonian object.
|
22
|
+
k_grid : :class:`numpy.ndarray`
|
23
|
+
List of k points.
|
24
|
+
band : int
|
25
|
+
Index of band for which the quantum metric is calculated.
|
26
|
+
|
27
|
+
Returns
|
28
|
+
-------
|
29
|
+
:class:`numpy.ndarray`
|
30
|
+
Quantum metric in the normal state.
|
31
|
+
|
32
|
+
"""
|
33
|
+
energies, bloch = h.diagonalize_nonint(k_grid)
|
34
|
+
|
35
|
+
number_k_points = len(k_grid)
|
36
|
+
|
37
|
+
quantum_geom_tensor = np.zeros(shape=(2, 2), dtype=np.complex64)
|
38
|
+
|
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
|
+
np.conjugate(bloch[k_index][:, band])
|
48
|
+
@ h_derivative_direction_1[k_index]
|
49
|
+
@ bloch[k_index][:, n]
|
50
|
+
)
|
51
|
+
* (
|
52
|
+
np.conjugate(bloch[k_index][:, n])
|
53
|
+
@ h_derivative_direction_2[k_index]
|
54
|
+
@ bloch[k_index][:, band]
|
55
|
+
)
|
56
|
+
/ (energies[k_index][band] - energies[k_index][n]) ** 2
|
57
|
+
)
|
58
|
+
|
59
|
+
return np.real(quantum_geom_tensor) / number_k_points
|
@@ -1,10 +1,59 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Functions to calculate the superfluid weight."""
|
6
|
+
|
1
7
|
import numpy as np
|
2
8
|
import numpy.typing as npt
|
3
9
|
|
4
|
-
from .
|
10
|
+
from .base_hamiltonian import BaseHamiltonian
|
11
|
+
|
12
|
+
|
13
|
+
def superfluid_weight(
|
14
|
+
h: BaseHamiltonian,
|
15
|
+
k_grid: npt.NDArray[np.float64],
|
16
|
+
) -> tuple[npt.NDArray[np.complex64], npt.NDArray[np.complex64]]:
|
17
|
+
"""Calculate the superfluid weight.
|
18
|
+
|
19
|
+
Parameters
|
20
|
+
----------
|
21
|
+
h : :class:`~quant_met.mean_field.Hamiltonian`
|
22
|
+
Hamiltonian.
|
23
|
+
k_grid : :class:`numpy.ndarray`
|
24
|
+
List of k points.
|
25
|
+
|
26
|
+
Returns
|
27
|
+
-------
|
28
|
+
:class:`numpy.ndarray`
|
29
|
+
Conventional contribution to the superfluid weight.
|
30
|
+
:class:`numpy.ndarray`
|
31
|
+
Geometric contribution to the superfluid weight.
|
32
|
+
|
33
|
+
"""
|
34
|
+
s_weight_conv = np.zeros(shape=(2, 2), dtype=np.complex64)
|
35
|
+
s_weight_geom = np.zeros(shape=(2, 2), dtype=np.complex64)
|
36
|
+
|
37
|
+
for i, direction_1 in enumerate(["x", "y"]):
|
38
|
+
for j, direction_2 in enumerate(["x", "y"]):
|
39
|
+
for k in k_grid:
|
40
|
+
c_mnpq = _c_factor(h, k)
|
41
|
+
j_up = _current_operator(h, direction_1, k)
|
42
|
+
j_down = _current_operator(h, direction_2, -k)
|
43
|
+
for m in range(h.number_of_bands):
|
44
|
+
for n in range(h.number_of_bands):
|
45
|
+
for p in range(h.number_of_bands):
|
46
|
+
for q in range(h.number_of_bands):
|
47
|
+
s_weight = c_mnpq[m, n, p, q] * j_up[m, n] * j_down[q, p]
|
48
|
+
if m == n and p == q:
|
49
|
+
s_weight_conv[i, j] += s_weight
|
50
|
+
else:
|
51
|
+
s_weight_geom[i, j] += s_weight
|
52
|
+
|
53
|
+
return s_weight_conv, s_weight_geom
|
5
54
|
|
6
55
|
|
7
|
-
def
|
56
|
+
def _current_operator(
|
8
57
|
h: BaseHamiltonian, direction: str, k: npt.NDArray[np.float64]
|
9
58
|
) -> npt.NDArray[np.complex64]:
|
10
59
|
j = np.zeros(shape=(h.number_of_bands, h.number_of_bands), dtype=np.complex64)
|
@@ -22,7 +71,7 @@ def calculate_current_operator(
|
|
22
71
|
return j
|
23
72
|
|
24
73
|
|
25
|
-
def
|
74
|
+
def _w_matrix(
|
26
75
|
h: BaseHamiltonian, k: npt.NDArray[np.float64]
|
27
76
|
) -> tuple[npt.NDArray[np.complex64], npt.NDArray[np.complex64]]:
|
28
77
|
_, bloch = h.diagonalize_nonint(k=k)
|
@@ -40,21 +89,17 @@ def calculate_w_matrix(
|
|
40
89
|
for i in range(2 * h.number_of_bands):
|
41
90
|
for m in range(h.number_of_bands):
|
42
91
|
w_minus[i, m] = (
|
43
|
-
np.tensordot(
|
44
|
-
np.conjugate(bloch[:, m]), np.array([0, 1]), axes=0
|
45
|
-
).reshape(-1)
|
92
|
+
np.tensordot(np.conjugate(bloch[:, m]), np.array([0, 1]), axes=0).reshape(-1)
|
46
93
|
@ bdg_functions[:, i]
|
47
94
|
)
|
48
95
|
|
49
96
|
return w_plus, w_minus
|
50
97
|
|
51
98
|
|
52
|
-
def
|
53
|
-
h: BaseHamiltonian, k: npt.NDArray[np.float64]
|
54
|
-
) -> npt.NDArray[np.complex64]:
|
99
|
+
def _c_factor(h: BaseHamiltonian, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
|
55
100
|
bdg_energies, _ = h.diagonalize_bdg(k)
|
56
|
-
w_plus, w_minus =
|
57
|
-
|
101
|
+
w_plus, w_minus = _w_matrix(h, k)
|
102
|
+
c_mnpq = np.zeros(
|
58
103
|
shape=(
|
59
104
|
h.number_of_bands,
|
60
105
|
h.number_of_bands,
|
@@ -68,63 +113,34 @@ def calculate_c_factor(
|
|
68
113
|
for n in range(h.number_of_bands):
|
69
114
|
for p in range(h.number_of_bands):
|
70
115
|
for q in range(h.number_of_bands):
|
71
|
-
|
116
|
+
c_tmp: float = 0
|
72
117
|
for i in range(2 * h.number_of_bands):
|
73
118
|
for j in range(2 * h.number_of_bands):
|
74
119
|
if bdg_energies[i] != bdg_energies[j]:
|
75
|
-
|
76
|
-
|
77
|
-
- fermi_dirac(bdg_energies[j])
|
120
|
+
c_tmp += (
|
121
|
+
_fermi_dirac(bdg_energies[i]) - _fermi_dirac(bdg_energies[j])
|
78
122
|
) / (bdg_energies[j] - bdg_energies[i])
|
79
123
|
else:
|
80
|
-
|
124
|
+
c_tmp -= _fermi_dirac_derivative()
|
81
125
|
|
82
|
-
|
126
|
+
c_tmp *= (
|
83
127
|
np.conjugate(w_minus[i, m])
|
84
128
|
* w_plus[j, n]
|
85
129
|
* np.conjugate(w_minus[j, p])
|
86
130
|
* w_minus[i, q]
|
87
131
|
)
|
88
132
|
|
89
|
-
|
133
|
+
c_mnpq[m, n, p, q] = 2 * c_tmp
|
90
134
|
|
91
|
-
return
|
135
|
+
return c_mnpq
|
92
136
|
|
93
137
|
|
94
|
-
def
|
138
|
+
def _fermi_dirac_derivative() -> float:
|
95
139
|
return 0
|
96
140
|
|
97
141
|
|
98
|
-
def
|
142
|
+
def _fermi_dirac(energy: np.float64) -> np.float64:
|
99
143
|
if energy > 0:
|
100
144
|
return np.float64(0)
|
101
|
-
else:
|
102
|
-
return np.float64(1)
|
103
|
-
|
104
|
-
|
105
|
-
def calculate_superfluid_weight(
|
106
|
-
h: BaseHamiltonian,
|
107
|
-
k_grid: npt.NDArray[np.float64],
|
108
|
-
direction_1: str,
|
109
|
-
direction_2: str,
|
110
|
-
) -> tuple[float, float]:
|
111
|
-
# number_k_points = len(k_grid)
|
112
|
-
|
113
|
-
s_weight_conv = 0
|
114
|
-
s_weight_geom = 0
|
115
|
-
|
116
|
-
for k in k_grid:
|
117
|
-
C_mnpq = calculate_c_factor(h, k)
|
118
|
-
j_up = calculate_current_operator(h, direction_1, k)
|
119
|
-
j_down = calculate_current_operator(h, direction_2, -k)
|
120
|
-
for m in range(h.number_of_bands):
|
121
|
-
for n in range(h.number_of_bands):
|
122
|
-
for p in range(h.number_of_bands):
|
123
|
-
for q in range(h.number_of_bands):
|
124
|
-
s_weight = C_mnpq[m, n, p, q] * j_up[m, n] * j_down[q, p]
|
125
|
-
if m == n and p == q:
|
126
|
-
s_weight_conv += s_weight
|
127
|
-
else:
|
128
|
-
s_weight_geom += s_weight
|
129
145
|
|
130
|
-
return
|
146
|
+
return np.float64(1)
|
quant_met/plotting/__init__.py
CHANGED
@@ -1,4 +1,25 @@
|
|
1
|
-
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""
|
6
|
+
Plotting
|
7
|
+
========
|
8
|
+
|
9
|
+
.. currentmodule:: quant_met.plotting
|
10
|
+
|
11
|
+
Functions
|
12
|
+
---------
|
13
|
+
|
14
|
+
.. autosummary::
|
15
|
+
:toctree: generated/
|
16
|
+
|
17
|
+
scatter_into_bz
|
18
|
+
plot_bandstructure
|
19
|
+
generate_bz_path
|
20
|
+
""" # noqa: D205, D400
|
21
|
+
|
22
|
+
from .plotting import generate_bz_path, plot_bandstructure, scatter_into_bz
|
2
23
|
|
3
24
|
__all__ = [
|
4
25
|
"scatter_into_bz",
|
@@ -0,0 +1,230 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Methods for plotting data."""
|
6
|
+
|
7
|
+
from typing import Any
|
8
|
+
|
9
|
+
import matplotlib.axes
|
10
|
+
import matplotlib.colors
|
11
|
+
import matplotlib.figure
|
12
|
+
import matplotlib.pyplot as plt
|
13
|
+
import numpy as np
|
14
|
+
import numpy.typing as npt
|
15
|
+
from matplotlib.collections import Collection, LineCollection
|
16
|
+
from numpy import dtype, generic, ndarray
|
17
|
+
|
18
|
+
|
19
|
+
def scatter_into_bz(
|
20
|
+
bz_corners: list[npt.NDArray[np.float64]],
|
21
|
+
k_points: npt.NDArray[np.float64],
|
22
|
+
data: npt.NDArray[np.float64] | None = None,
|
23
|
+
data_label: str | None = None,
|
24
|
+
fig_in: matplotlib.figure.Figure | None = None,
|
25
|
+
ax_in: matplotlib.axes.Axes | None = None,
|
26
|
+
) -> matplotlib.figure.Figure:
|
27
|
+
"""Scatter a list of points into the brillouin zone.
|
28
|
+
|
29
|
+
Parameters
|
30
|
+
----------
|
31
|
+
bz_corners : list[:class:`numpy.ndarray`]
|
32
|
+
Corner points defining the brillouin zone.
|
33
|
+
k_points : :class:`numpy.ndarray`
|
34
|
+
List of k points.
|
35
|
+
data : :class:`numpy.ndarray`, optional
|
36
|
+
Data to put on the k points.
|
37
|
+
data_label : :class:`str`, optional
|
38
|
+
Label for the data.
|
39
|
+
fig_in : :class:`matplotlib.figure.Figure`, optional
|
40
|
+
Figure that holds the axes. If not provided, a new figure and ax is created.
|
41
|
+
ax_in : :class:`matplotlib.axes.Axes`, optional
|
42
|
+
Ax to plot the data in. If not provided, a new figure and ax is created.
|
43
|
+
|
44
|
+
Returns
|
45
|
+
-------
|
46
|
+
:obj:`matplotlib.figure.Figure`
|
47
|
+
Figure with the data plotted onto the axis.
|
48
|
+
|
49
|
+
"""
|
50
|
+
if fig_in is None or ax_in is None:
|
51
|
+
fig, ax = plt.subplots()
|
52
|
+
else:
|
53
|
+
fig, ax = fig_in, ax_in
|
54
|
+
|
55
|
+
if data is not None:
|
56
|
+
x_coords, y_coords = zip(*k_points, strict=True)
|
57
|
+
scatter = ax.scatter(x=x_coords, y=y_coords, c=data, cmap="viridis")
|
58
|
+
fig.colorbar(scatter, ax=ax, fraction=0.046, pad=0.04, label=data_label)
|
59
|
+
else:
|
60
|
+
x_coords, y_coords = zip(*k_points, strict=True)
|
61
|
+
ax.scatter(x=x_coords, y=y_coords)
|
62
|
+
|
63
|
+
bz_corner_x, bz_corners_y = zip(*bz_corners, strict=True)
|
64
|
+
ax.scatter(x=bz_corner_x, y=bz_corners_y, alpha=0.8)
|
65
|
+
ax.set_aspect("equal", adjustable="box")
|
66
|
+
ax.set_xlabel(r"$k_x\ [1/a_0]$")
|
67
|
+
ax.set_ylabel(r"$k_y\ [1/a_0]$")
|
68
|
+
|
69
|
+
return fig
|
70
|
+
|
71
|
+
|
72
|
+
def plot_bandstructure(
|
73
|
+
bands: npt.NDArray[np.float64],
|
74
|
+
k_point_list: npt.NDArray[np.float64],
|
75
|
+
ticks: list[float],
|
76
|
+
labels: list[str],
|
77
|
+
overlaps: npt.NDArray[np.float64] | None = None,
|
78
|
+
overlap_labels: list[str] | None = None,
|
79
|
+
fig_in: matplotlib.figure.Figure | None = None,
|
80
|
+
ax_in: matplotlib.axes.Axes | None = None,
|
81
|
+
) -> matplotlib.figure.Figure:
|
82
|
+
"""Plot bands along a k space path.
|
83
|
+
|
84
|
+
To have a plot that respects the distances in k space and generate everything that is needed for
|
85
|
+
plotting, use the function :func:`~quant_met.plotting.generate_bz_path`.
|
86
|
+
|
87
|
+
Parameters
|
88
|
+
----------
|
89
|
+
bands : :class:`numpy.ndarray`
|
90
|
+
k_point_list : :class:`numpy.ndarray`
|
91
|
+
List of points to plot against. This is not a list of two-dimensional k-points!
|
92
|
+
ticks : list(float)
|
93
|
+
Position for ticks.
|
94
|
+
labels : list(str)
|
95
|
+
Labels on ticks.
|
96
|
+
overlaps : :class:`numpy.ndarray`, optional
|
97
|
+
Overlaps.
|
98
|
+
overlap_labels : list(str), optional
|
99
|
+
Labels to put on overlaps.
|
100
|
+
fig_in : :class:`matplotlib.figure.Figure`, optional
|
101
|
+
Figure that holds the axes. If not provided, a new figure and ax is created.
|
102
|
+
ax_in : :class:`matplotlib.axes.Axes`, optional
|
103
|
+
Ax to plot the data in. If not provided, a new figure and ax is created.
|
104
|
+
|
105
|
+
Returns
|
106
|
+
-------
|
107
|
+
:obj:`matplotlib.figure.Figure`
|
108
|
+
Figure with the data plotted onto the axis.
|
109
|
+
|
110
|
+
|
111
|
+
"""
|
112
|
+
if fig_in is None or ax_in is None:
|
113
|
+
fig, ax = plt.subplots()
|
114
|
+
else:
|
115
|
+
fig, ax = fig_in, ax_in
|
116
|
+
|
117
|
+
ax.axhline(y=0, alpha=0.7, linestyle="--", color="black")
|
118
|
+
|
119
|
+
if overlaps is None:
|
120
|
+
for band in bands:
|
121
|
+
ax.plot(k_point_list, band)
|
122
|
+
else:
|
123
|
+
line = Collection()
|
124
|
+
for band, wx in zip(bands, overlaps, strict=True):
|
125
|
+
points = np.array([k_point_list, band]).T.reshape(-1, 1, 2)
|
126
|
+
segments = np.concatenate([points[:-1], points[1:]], axis=1)
|
127
|
+
|
128
|
+
norm = matplotlib.colors.Normalize(-1, 1)
|
129
|
+
lc = LineCollection(segments, cmap="seismic", norm=norm)
|
130
|
+
lc.set_array(wx)
|
131
|
+
lc.set_linewidth(2)
|
132
|
+
line = ax.add_collection(lc)
|
133
|
+
|
134
|
+
colorbar = fig.colorbar(line, fraction=0.046, pad=0.04, ax=ax)
|
135
|
+
color_ticks = [-1, 1]
|
136
|
+
colorbar.set_ticks(ticks=color_ticks, labels=overlap_labels)
|
137
|
+
|
138
|
+
ax.set_ylim(
|
139
|
+
top=float(np.max(bands) + 0.1 * np.max(bands)),
|
140
|
+
bottom=float(np.min(bands) - 0.1 * np.abs(np.min(bands))),
|
141
|
+
)
|
142
|
+
ax.set_box_aspect(1)
|
143
|
+
ax.set_xticks(ticks, labels)
|
144
|
+
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
|
+
|
149
|
+
return fig
|
150
|
+
|
151
|
+
|
152
|
+
def _generate_part_of_path(
|
153
|
+
p_0: npt.NDArray[np.float64],
|
154
|
+
p_1: npt.NDArray[np.float64],
|
155
|
+
n: int,
|
156
|
+
length_whole_path: int,
|
157
|
+
) -> npt.NDArray[np.float64]:
|
158
|
+
distance = np.linalg.norm(p_1 - p_0)
|
159
|
+
number_of_points = int(n * distance / length_whole_path) + 1
|
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.
|
178
|
+
|
179
|
+
Parameters
|
180
|
+
----------
|
181
|
+
points : :class:`numpy.ndarray`
|
182
|
+
Test
|
183
|
+
number_of_points: int
|
184
|
+
Number of point in the whole path.
|
185
|
+
|
186
|
+
Returns
|
187
|
+
-------
|
188
|
+
:class:`numpy.ndarray`
|
189
|
+
List of two-dimensional k points.
|
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.
|
196
|
+
|
197
|
+
"""
|
198
|
+
n = number_of_points
|
199
|
+
|
200
|
+
cycle = [np.linalg.norm(points[i][0] - points[i + 1][0]) for i in range(len(points) - 1)]
|
201
|
+
cycle.append(np.linalg.norm(points[-1][0] - points[0][0]))
|
202
|
+
|
203
|
+
length_whole_path = np.sum(np.array([cycle]))
|
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
|
+
]
|
221
|
+
)
|
222
|
+
|
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
|
+
|
230
|
+
return whole_path, whole_path_plot, ticks, labels
|
quant_met/utils.py
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""
|
6
|
+
Utility functions (:mod:`quant_met.utils`)
|
7
|
+
==========================================
|
8
|
+
|
9
|
+
.. currentmodule:: quant_met.utils
|
10
|
+
|
11
|
+
Functions
|
12
|
+
---------
|
13
|
+
|
14
|
+
.. autosummary::
|
15
|
+
:toctree: generated/
|
16
|
+
|
17
|
+
generate_uniform_grid - Generate a uniform grid of points in 2D.
|
18
|
+
""" # noqa: D205, D400
|
19
|
+
|
1
20
|
import numpy as np
|
2
21
|
import numpy.typing as npt
|
3
22
|
|
@@ -9,10 +28,34 @@ def generate_uniform_grid(
|
|
9
28
|
corner_2: npt.NDArray[np.float64],
|
10
29
|
origin: npt.NDArray[np.float64],
|
11
30
|
) -> npt.NDArray[np.float64]:
|
31
|
+
"""
|
32
|
+
Generate a uniform grid of points in 2D.
|
33
|
+
|
34
|
+
Parameters
|
35
|
+
----------
|
36
|
+
ncols : int
|
37
|
+
Number of columns
|
38
|
+
nrows : int
|
39
|
+
Number of rows
|
40
|
+
corner_1 : :py:class:`numpy.ndarray`
|
41
|
+
First corner vector
|
42
|
+
corner_2 : :py:class:`numpy.ndarray`
|
43
|
+
Second corner vector
|
44
|
+
origin : :py:class:`numpy.ndarray`
|
45
|
+
Origin point
|
46
|
+
|
47
|
+
Returns
|
48
|
+
-------
|
49
|
+
:py:class:`numpy.ndarray`
|
50
|
+
Grid
|
51
|
+
|
52
|
+
"""
|
12
53
|
if ncols <= 1 or nrows <= 1:
|
13
|
-
|
54
|
+
msg = "Number of columns and rows must be greater than 1."
|
55
|
+
raise ValueError(msg)
|
14
56
|
if np.linalg.norm(corner_1) == 0 or np.linalg.norm(corner_2) == 0:
|
15
|
-
|
57
|
+
msg = "Vectors to the corners cannot be zero."
|
58
|
+
raise ValueError(msg)
|
16
59
|
|
17
60
|
grid: npt.NDArray[np.float64] = np.concatenate(
|
18
61
|
[
|
@@ -0,0 +1,9 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024-present Tjark <tsievers@physnet.uni-hamburg.de>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -1,22 +1,26 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: quant-met
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.3
|
4
4
|
Summary: Calculate superconductivity in flat-band systems.
|
5
5
|
Author: Tjark Sievers
|
6
6
|
Author-email: tsievers@physnet.uni-hamburg.de
|
7
|
-
Requires-Python: >=3.
|
7
|
+
Requires-Python: >=3.11,<4.0
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
9
|
-
Classifier: Programming Language :: Python :: 3.10
|
10
9
|
Classifier: Programming Language :: Python :: 3.11
|
11
10
|
Classifier: Programming Language :: Python :: 3.12
|
12
11
|
Requires-Dist: h5py (>=3.11.0,<4.0.0)
|
13
|
-
Requires-Dist: matplotlib (>=3.
|
14
|
-
Requires-Dist: numpy (>=
|
12
|
+
Requires-Dist: matplotlib (>=3.9.1,<4.0.0)
|
13
|
+
Requires-Dist: numpy (>=2.0.0,<3.0.0)
|
15
14
|
Requires-Dist: pandas (>=2.2.2,<3.0.0)
|
16
|
-
Requires-Dist: scipy (>=1.
|
17
|
-
Requires-Dist: sympy (>=1.12,<2.0)
|
15
|
+
Requires-Dist: scipy (>=1.14.0,<2.0.0)
|
18
16
|
Description-Content-Type: text/markdown
|
19
17
|
|
18
|
+
<!--
|
19
|
+
SPDX-FileCopyrightText: 2024 Tjark Sievers
|
20
|
+
|
21
|
+
SPDX-License-Identifier: MIT
|
22
|
+
-->
|
23
|
+
|
20
24
|
# quant-met
|
21
25
|
|
22
26
|
[](https://github.com/Ruberhauptmann/quant-met/actions/workflows/test.yml)
|