quant-met 0.0.15__py3-none-any.whl → 0.0.17__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 +1 -1
- quant_met/geometry/base_lattice.py +6 -6
- quant_met/geometry/bz_path.py +6 -6
- quant_met/geometry/graphene.py +3 -3
- quant_met/geometry/square.py +3 -3
- quant_met/mean_field/__init__.py +3 -3
- quant_met/mean_field/hamiltonians/__init__.py +1 -1
- quant_met/mean_field/hamiltonians/base_hamiltonian.py +180 -53
- quant_met/mean_field/hamiltonians/dressed_graphene.py +6 -6
- quant_met/mean_field/hamiltonians/graphene.py +6 -6
- quant_met/mean_field/hamiltonians/one_band_tight_binding.py +6 -6
- quant_met/mean_field/hamiltonians/three_band_tight_binding.py +6 -6
- quant_met/mean_field/hamiltonians/two_band_tight_binding.py +6 -6
- quant_met/mean_field/quantum_metric.py +3 -3
- quant_met/mean_field/search_crit_temp.py +5 -6
- quant_met/mean_field/self_consistency.py +13 -9
- quant_met/mean_field/superfluid_weight.py +23 -20
- quant_met/parameters/__init__.py +5 -5
- quant_met/parameters/hamiltonians.py +8 -8
- quant_met/plotting/__init__.py +1 -1
- quant_met/plotting/plotting.py +9 -9
- quant_met/utils.py +27 -5
- {quant_met-0.0.15.dist-info → quant_met-0.0.17.dist-info}/METADATA +21 -23
- quant_met-0.0.17.dist-info/RECORD +35 -0
- {quant_met-0.0.15.dist-info → quant_met-0.0.17.dist-info}/WHEEL +1 -1
- quant_met-0.0.17.dist-info/entry_points.txt +2 -0
- quant_met-0.0.15.dist-info/LICENSES/MIT.txt +0 -9
- quant_met-0.0.15.dist-info/RECORD +0 -36
- quant_met-0.0.15.dist-info/entry_points.txt +0 -3
- {quant_met-0.0.15.dist-info → quant_met-0.0.17.dist-info/licenses}/LICENSE.txt +0 -0
quant_met/geometry/__init__.py
CHANGED
@@ -32,4 +32,4 @@ from .bz_path import generate_bz_path
|
|
32
32
|
from .graphene import GrapheneLattice
|
33
33
|
from .square import SquareLattice
|
34
34
|
|
35
|
-
__all__ = ["
|
35
|
+
__all__ = ["BaseLattice", "GrapheneLattice", "SquareLattice", "generate_bz_path"]
|
@@ -25,7 +25,7 @@ class BaseLattice(ABC):
|
|
25
25
|
|
26
26
|
@property
|
27
27
|
@abstractmethod
|
28
|
-
def bz_corners(self) -> npt.NDArray[np.
|
28
|
+
def bz_corners(self) -> npt.NDArray[np.floating]: # pragma: no cover
|
29
29
|
"""Corners of the BZ."""
|
30
30
|
raise NotImplementedError
|
31
31
|
|
@@ -33,7 +33,7 @@ class BaseLattice(ABC):
|
|
33
33
|
@abstractmethod
|
34
34
|
def reciprocal_basis(
|
35
35
|
self,
|
36
|
-
) -> tuple[npt.NDArray[np.
|
36
|
+
) -> tuple[npt.NDArray[np.floating], npt.NDArray[np.floating]]: # pragma: no cover
|
37
37
|
"""Reciprocal basis vectors."""
|
38
38
|
raise NotImplementedError
|
39
39
|
|
@@ -41,11 +41,11 @@ class BaseLattice(ABC):
|
|
41
41
|
@abstractmethod
|
42
42
|
def high_symmetry_points(
|
43
43
|
self,
|
44
|
-
) -> tuple[tuple[npt.NDArray[np.
|
44
|
+
) -> tuple[tuple[npt.NDArray[np.floating], str], ...]: # pragma: no cover
|
45
45
|
"""Tuple of high symmetry points and names."""
|
46
46
|
raise NotImplementedError
|
47
47
|
|
48
|
-
def generate_bz_grid(self, ncols: int, nrows: int) -> npt.NDArray[np.
|
48
|
+
def generate_bz_grid(self, ncols: int, nrows: int) -> npt.NDArray[np.floating]:
|
49
49
|
"""Generate a grid in the BZ.
|
50
50
|
|
51
51
|
Parameters
|
@@ -72,8 +72,8 @@ class BaseLattice(ABC):
|
|
72
72
|
def generate_high_symmetry_path(
|
73
73
|
self, number_of_points: int
|
74
74
|
) -> tuple[
|
75
|
-
npt.NDArray[np.
|
76
|
-
npt.NDArray[np.
|
75
|
+
npt.NDArray[np.floating],
|
76
|
+
npt.NDArray[np.floating],
|
77
77
|
list[float],
|
78
78
|
list[str],
|
79
79
|
]:
|
quant_met/geometry/bz_path.py
CHANGED
@@ -9,11 +9,11 @@ import numpy.typing as npt
|
|
9
9
|
|
10
10
|
|
11
11
|
def _generate_part_of_path(
|
12
|
-
p_0: npt.NDArray[np.
|
13
|
-
p_1: npt.NDArray[np.
|
12
|
+
p_0: npt.NDArray[np.floating],
|
13
|
+
p_1: npt.NDArray[np.floating],
|
14
14
|
n: int,
|
15
15
|
length_whole_path: int,
|
16
|
-
) -> npt.NDArray[np.
|
16
|
+
) -> npt.NDArray[np.floating]:
|
17
17
|
distance = np.linalg.norm(p_1 - p_0)
|
18
18
|
number_of_points = int(n * distance / length_whole_path) + 1
|
19
19
|
|
@@ -26,10 +26,10 @@ def _generate_part_of_path(
|
|
26
26
|
|
27
27
|
|
28
28
|
def generate_bz_path(
|
29
|
-
points: list[tuple[npt.NDArray[np.
|
29
|
+
points: list[tuple[npt.NDArray[np.floating], str]], number_of_points: int = 1000
|
30
30
|
) -> tuple[
|
31
|
-
npt.NDArray[np.
|
32
|
-
npt.NDArray[np.
|
31
|
+
npt.NDArray[np.floating],
|
32
|
+
npt.NDArray[np.floating],
|
33
33
|
list[float],
|
34
34
|
list[str],
|
35
35
|
]:
|
quant_met/geometry/graphene.py
CHANGED
@@ -35,13 +35,13 @@ class GrapheneLattice(BaseLattice):
|
|
35
35
|
return self._lattice_constant
|
36
36
|
|
37
37
|
@property
|
38
|
-
def bz_corners(self) -> npt.NDArray[np.
|
38
|
+
def bz_corners(self) -> npt.NDArray[np.floating]: # noqa: D102
|
39
39
|
return self._bz_corners
|
40
40
|
|
41
41
|
@property
|
42
|
-
def reciprocal_basis(self) -> tuple[npt.NDArray[np.
|
42
|
+
def reciprocal_basis(self) -> tuple[npt.NDArray[np.floating], npt.NDArray[np.floating]]: # noqa: D102
|
43
43
|
return self._reciprocal_basis
|
44
44
|
|
45
45
|
@property
|
46
|
-
def high_symmetry_points(self) -> tuple[tuple[npt.NDArray[np.
|
46
|
+
def high_symmetry_points(self) -> tuple[tuple[npt.NDArray[np.floating], str], ...]: # noqa: D102
|
47
47
|
return self._high_symmetry_points
|
quant_met/geometry/square.py
CHANGED
@@ -34,13 +34,13 @@ class SquareLattice(BaseLattice):
|
|
34
34
|
return self._lattice_constant
|
35
35
|
|
36
36
|
@property
|
37
|
-
def bz_corners(self) -> npt.NDArray[np.
|
37
|
+
def bz_corners(self) -> npt.NDArray[np.floating]: # noqa: D102 # pragma: no cover
|
38
38
|
return self._bz_corners
|
39
39
|
|
40
40
|
@property
|
41
|
-
def reciprocal_basis(self) -> tuple[npt.NDArray[np.
|
41
|
+
def reciprocal_basis(self) -> tuple[npt.NDArray[np.floating], npt.NDArray[np.floating]]: # noqa: D102
|
42
42
|
return self._reciprocal_basis
|
43
43
|
|
44
44
|
@property
|
45
|
-
def high_symmetry_points(self) -> tuple[tuple[npt.NDArray[np.
|
45
|
+
def high_symmetry_points(self) -> tuple[tuple[npt.NDArray[np.floating], str], ...]: # noqa: D102
|
46
46
|
return self._high_symmetry_points
|
quant_met/mean_field/__init__.py
CHANGED
@@ -35,9 +35,9 @@ from .self_consistency import self_consistency_loop
|
|
35
35
|
from .superfluid_weight import superfluid_weight
|
36
36
|
|
37
37
|
__all__ = [
|
38
|
-
"
|
38
|
+
"hamiltonians",
|
39
39
|
"quantum_metric",
|
40
|
-
"self_consistency_loop",
|
41
40
|
"search_crit_temp",
|
42
|
-
"
|
41
|
+
"self_consistency_loop",
|
42
|
+
"superfluid_weight",
|
43
43
|
]
|
@@ -30,4 +30,4 @@ from .one_band_tight_binding import OneBand
|
|
30
30
|
from .three_band_tight_binding import ThreeBand
|
31
31
|
from .two_band_tight_binding import TwoBand
|
32
32
|
|
33
|
-
__all__ = ["BaseHamiltonian", "
|
33
|
+
__all__ = ["BaseHamiltonian", "DressedGraphene", "Graphene", "OneBand", "ThreeBand", "TwoBand"]
|
@@ -12,10 +12,12 @@ import h5py
|
|
12
12
|
import numpy as np
|
13
13
|
import numpy.typing as npt
|
14
14
|
import pandas as pd
|
15
|
+
from numba import jit
|
15
16
|
|
16
17
|
from quant_met.geometry import BaseLattice
|
17
18
|
from quant_met.mean_field._utils import _check_valid_array
|
18
19
|
from quant_met.parameters.hamiltonians import GenericParameters, HamiltonianParameters
|
20
|
+
from quant_met.utils import fermi_dirac
|
19
21
|
|
20
22
|
GenericHamiltonian = TypeVar("GenericHamiltonian", bound="BaseHamiltonian[HamiltonianParameters]")
|
21
23
|
|
@@ -64,7 +66,7 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
64
66
|
self.lattice = self.setup_lattice(parameters)
|
65
67
|
self.hubbard_int_orbital_basis = parameters.hubbard_int_orbital_basis
|
66
68
|
self.number_of_bands = len(self.hubbard_int_orbital_basis)
|
67
|
-
self.delta_orbital_basis = np.zeros(self.number_of_bands, dtype=np.
|
69
|
+
self.delta_orbital_basis = np.zeros(self.number_of_bands, dtype=np.complex128)
|
68
70
|
|
69
71
|
@abstractmethod
|
70
72
|
def setup_lattice(self, parameters: GenericParameters) -> BaseLattice: # pragma: no cover
|
@@ -97,8 +99,8 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
97
99
|
|
98
100
|
@abstractmethod
|
99
101
|
def hamiltonian(
|
100
|
-
self, k: npt.NDArray[np.
|
101
|
-
) -> npt.NDArray[np.
|
102
|
+
self, k: npt.NDArray[np.floating]
|
103
|
+
) -> npt.NDArray[np.complexfloating]: # pragma: no cover
|
102
104
|
"""Return the normal state Hamiltonian.
|
103
105
|
|
104
106
|
Parameters
|
@@ -114,8 +116,8 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
114
116
|
|
115
117
|
@abstractmethod
|
116
118
|
def hamiltonian_derivative(
|
117
|
-
self, k: npt.NDArray[np.
|
118
|
-
) -> npt.NDArray[np.
|
119
|
+
self, k: npt.NDArray[np.floating], direction: str
|
120
|
+
) -> npt.NDArray[np.complexfloating]: # pragma: no cover
|
119
121
|
"""Calculate the spatial derivative of the Hamiltonian.
|
120
122
|
|
121
123
|
Parameters
|
@@ -174,7 +176,7 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
174
176
|
parameters = parameters_model.model_validate(config_dict)
|
175
177
|
return cls(parameters=parameters)
|
176
178
|
|
177
|
-
def bdg_hamiltonian(self, k: npt.NDArray[np.
|
179
|
+
def bdg_hamiltonian(self, k: npt.NDArray[np.floating]) -> npt.NDArray[np.complexfloating]:
|
178
180
|
"""Generate the Bogoliubov-de Gennes (BdG) Hamiltonian.
|
179
181
|
|
180
182
|
The BdG Hamiltonian incorporates pairing interactions and is used to
|
@@ -197,7 +199,8 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
197
199
|
k = np.expand_dims(k, axis=0)
|
198
200
|
|
199
201
|
h = np.zeros(
|
200
|
-
(k.shape[0], 2 * self.number_of_bands, 2 * self.number_of_bands),
|
202
|
+
(k.shape[0], 2 * self.number_of_bands, 2 * self.number_of_bands),
|
203
|
+
dtype=np.complex128,
|
201
204
|
)
|
202
205
|
|
203
206
|
h[:, 0 : self.number_of_bands, 0 : self.number_of_bands] = self.hamiltonian(k)
|
@@ -219,8 +222,8 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
219
222
|
return h.squeeze()
|
220
223
|
|
221
224
|
def bdg_hamiltonian_derivative(
|
222
|
-
self, k: npt.NDArray[np.
|
223
|
-
) -> npt.NDArray[np.
|
225
|
+
self, k: npt.NDArray[np.floating], direction: str
|
226
|
+
) -> npt.NDArray[np.complexfloating]:
|
224
227
|
"""Calculate the derivative of the BdG Hamiltonian.
|
225
228
|
|
226
229
|
This method computes the spatial derivative of the Bogoliubov-de Gennes
|
@@ -243,7 +246,8 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
243
246
|
k = np.expand_dims(k, axis=0)
|
244
247
|
|
245
248
|
h = np.zeros(
|
246
|
-
(k.shape[0], 2 * self.number_of_bands, 2 * self.number_of_bands),
|
249
|
+
(k.shape[0], 2 * self.number_of_bands, 2 * self.number_of_bands),
|
250
|
+
dtype=np.complex128,
|
247
251
|
)
|
248
252
|
|
249
253
|
h[:, 0 : self.number_of_bands, 0 : self.number_of_bands] = self.hamiltonian_derivative(
|
@@ -258,8 +262,8 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
258
262
|
return h.squeeze()
|
259
263
|
|
260
264
|
def diagonalize_nonint(
|
261
|
-
self, k: npt.NDArray[np.
|
262
|
-
) -> tuple[npt.NDArray[np.
|
265
|
+
self, k: npt.NDArray[np.floating]
|
266
|
+
) -> tuple[npt.NDArray[np.floating], npt.NDArray[np.floating]]:
|
263
267
|
"""Diagonalizes the normal state Hamiltonian.
|
264
268
|
|
265
269
|
This method computes the eigenvalues and eigenvectors of the normal state
|
@@ -296,8 +300,8 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
296
300
|
|
297
301
|
def diagonalize_bdg(
|
298
302
|
self,
|
299
|
-
k: npt.NDArray[np.
|
300
|
-
) -> tuple[npt.NDArray[np.
|
303
|
+
k: npt.NDArray[np.floating],
|
304
|
+
) -> tuple[npt.NDArray[np.floating], npt.NDArray[np.complexfloating]]:
|
301
305
|
"""Diagonalizes the BdG Hamiltonian.
|
302
306
|
|
303
307
|
This method computes the eigenvalues and eigenvectors of the Bogoliubov-de
|
@@ -323,7 +327,7 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
323
327
|
|
324
328
|
bdg_wavefunctions = np.zeros(
|
325
329
|
(len(k), 2 * self.number_of_bands, 2 * self.number_of_bands),
|
326
|
-
dtype=np.
|
330
|
+
dtype=np.complex128,
|
327
331
|
)
|
328
332
|
bdg_energies = np.zeros((len(k), 2 * self.number_of_bands))
|
329
333
|
|
@@ -332,10 +336,34 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
332
336
|
|
333
337
|
return bdg_energies.squeeze(), bdg_wavefunctions.squeeze()
|
334
338
|
|
335
|
-
def gap_equation(
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
+
def gap_equation(self, k: npt.NDArray[np.floating]) -> npt.NDArray[np.complexfloating]:
|
340
|
+
"""Gap equation.
|
341
|
+
|
342
|
+
Parameters
|
343
|
+
----------
|
344
|
+
k : :class:`numpy.ndarray`
|
345
|
+
k grid
|
346
|
+
|
347
|
+
Returns
|
348
|
+
-------
|
349
|
+
New delta
|
350
|
+
"""
|
351
|
+
bdg_energies, bdg_wavefunctions = self.diagonalize_bdg(k=k)
|
352
|
+
delta = np.zeros(self.number_of_bands, dtype=np.complex128)
|
353
|
+
return self.gap_equation_loop(
|
354
|
+
bdg_energies, bdg_wavefunctions, delta, self.beta, self.hubbard_int_orbital_basis, k
|
355
|
+
)
|
356
|
+
|
357
|
+
@staticmethod
|
358
|
+
@jit
|
359
|
+
def gap_equation_loop(
|
360
|
+
bdg_energies: npt.NDArray[np.float64],
|
361
|
+
bdg_wavefunctions: npt.NDArray[np.complex128],
|
362
|
+
delta: npt.NDArray[np.float64],
|
363
|
+
beta: float,
|
364
|
+
hubbard_int_orbital_basis: npt.NDArray[np.float64],
|
365
|
+
k: npt.NDArray[np.floating],
|
366
|
+
) -> npt.NDArray[np.complexfloating]:
|
339
367
|
"""Calculate the gap equation.
|
340
368
|
|
341
369
|
The gap equation determines the order parameter for superconductivity by
|
@@ -343,6 +371,16 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
343
371
|
|
344
372
|
Parameters
|
345
373
|
----------
|
374
|
+
bdg_energies : :class:`numpy.ndarray`
|
375
|
+
BdG energies
|
376
|
+
bdg_wavefunctions : :class:`numpy.ndarray`
|
377
|
+
BdG wavefunctions
|
378
|
+
delta : :class:`numpy.ndarray`
|
379
|
+
Delta
|
380
|
+
beta : :class:`float`
|
381
|
+
Beta
|
382
|
+
hubbard_int_orbital_basis : :class:`numpy.ndarray`
|
383
|
+
Hubard interaction in orbital basis
|
346
384
|
k : :class:`numpy.ndarray`
|
347
385
|
List of k points in reciprocal space.
|
348
386
|
|
@@ -351,29 +389,27 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
351
389
|
:class:`numpy.ndarray`
|
352
390
|
New pairing gap in orbital basis, adjusted to remove global phase.
|
353
391
|
"""
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
for i in range(self.number_of_bands):
|
392
|
+
number_of_bands = len(delta)
|
393
|
+
for i in range(number_of_bands):
|
358
394
|
sum_tmp = 0
|
359
|
-
for j in range(2 *
|
395
|
+
for j in range(2 * number_of_bands):
|
360
396
|
for k_index in range(len(k)):
|
361
397
|
sum_tmp += (
|
362
398
|
np.conjugate(bdg_wavefunctions[k_index, i, j])
|
363
|
-
* bdg_wavefunctions[k_index, i +
|
364
|
-
*
|
399
|
+
* bdg_wavefunctions[k_index, i + number_of_bands, j]
|
400
|
+
* fermi_dirac(bdg_energies[k_index, j].item(), beta)
|
365
401
|
)
|
366
|
-
delta[i] = (-
|
402
|
+
delta[i] = (-hubbard_int_orbital_basis[i] * sum_tmp / len(k)).conjugate()
|
367
403
|
|
368
|
-
delta_without_phase: npt.NDArray[np.
|
404
|
+
delta_without_phase: npt.NDArray[np.complexfloating] = delta * np.exp(
|
369
405
|
-1j * np.angle(delta[np.argmax(np.abs(delta))])
|
370
406
|
)
|
371
407
|
return delta_without_phase
|
372
408
|
|
373
409
|
def calculate_bandstructure(
|
374
410
|
self,
|
375
|
-
k: npt.NDArray[np.
|
376
|
-
overlaps: tuple[npt.NDArray[np.
|
411
|
+
k: npt.NDArray[np.floating],
|
412
|
+
overlaps: tuple[npt.NDArray[np.floating], npt.NDArray[np.floating]] | None = None,
|
377
413
|
) -> pd.DataFrame:
|
378
414
|
"""Calculate the band structure.
|
379
415
|
|
@@ -401,24 +437,24 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
401
437
|
energies, wavefunctions = self.diagonalize_nonint(k)
|
402
438
|
|
403
439
|
for i, (energy_k, wavefunction_k) in enumerate(zip(energies, wavefunctions, strict=False)):
|
404
|
-
if
|
440
|
+
if np.ndim(energy_k) == 0:
|
405
441
|
results.loc[i, "band"] = energy_k
|
406
442
|
else:
|
407
443
|
for band_index in range(self.number_of_bands):
|
408
|
-
results.loc[i, f"band_{band_index}"] = energy_k[band_index]
|
444
|
+
results.loc[i, f"band_{band_index}"] = energy_k[band_index] # type: ignore[index]
|
409
445
|
|
410
446
|
if overlaps is not None:
|
411
447
|
results.loc[i, f"wx_{band_index}"] = (
|
412
|
-
np.abs(np.dot(wavefunction_k[:, band_index], overlaps[0])) ** 2
|
413
|
-
- np.abs(np.dot(wavefunction_k[:, band_index], overlaps[1])) ** 2
|
448
|
+
np.abs(np.dot(wavefunction_k[:, band_index], overlaps[0])) ** 2 # type: ignore[index]
|
449
|
+
- np.abs(np.dot(wavefunction_k[:, band_index], overlaps[1])) ** 2 # type: ignore[index]
|
414
450
|
)
|
415
451
|
|
416
452
|
return results
|
417
453
|
|
418
454
|
def calculate_density_of_states(
|
419
455
|
self,
|
420
|
-
k: npt.NDArray[np.
|
421
|
-
) -> tuple[npt.NDArray[np.
|
456
|
+
k: npt.NDArray[np.floating],
|
457
|
+
) -> tuple[npt.NDArray[np.floating], npt.NDArray[np.floating]]:
|
422
458
|
"""Calculate the density of states (DOS).
|
423
459
|
|
424
460
|
This method computes the density of states by evaluating the eigenvalues
|
@@ -437,16 +473,35 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
437
473
|
- numpy.ndarray: The density of states corresponding to each energy level.
|
438
474
|
"""
|
439
475
|
bands, _ = self.diagonalize_bdg(k=k)
|
440
|
-
|
441
|
-
|
476
|
+
gap_fraction = 10
|
477
|
+
energies = np.concatenate(
|
478
|
+
[
|
479
|
+
np.linspace(
|
480
|
+
start=np.min(bands),
|
481
|
+
stop=-gap_fraction * np.max(np.abs(self.delta_orbital_basis)),
|
482
|
+
num=100,
|
483
|
+
),
|
484
|
+
np.linspace(
|
485
|
+
start=-gap_fraction * np.max(np.abs(self.delta_orbital_basis)),
|
486
|
+
stop=gap_fraction * np.max(np.abs(self.delta_orbital_basis)),
|
487
|
+
num=200,
|
488
|
+
),
|
489
|
+
np.linspace(
|
490
|
+
start=gap_fraction * np.max(np.abs(self.delta_orbital_basis)),
|
491
|
+
stop=np.max(bands),
|
492
|
+
num=100,
|
493
|
+
),
|
494
|
+
]
|
495
|
+
)
|
496
|
+
density_of_states = np.zeros(shape=energies.shape, dtype=np.floating)
|
442
497
|
|
443
498
|
for i, energy in enumerate(energies):
|
444
499
|
density_of_states[i] = np.sum(
|
445
|
-
_gaussian(x=(energy - bands.flatten()), sigma=
|
500
|
+
_gaussian(x=(energy - bands.flatten()), sigma=0.01)
|
446
501
|
) / len(k)
|
447
502
|
return energies, density_of_states
|
448
503
|
|
449
|
-
def calculate_spectral_gap(self, k: npt.NDArray[np.
|
504
|
+
def calculate_spectral_gap(self, k: npt.NDArray[np.floating]) -> float:
|
450
505
|
"""Calculate the spectral gap.
|
451
506
|
|
452
507
|
This method evaluates the spectral gap of the system by examining the
|
@@ -466,13 +521,15 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
466
521
|
"""
|
467
522
|
energies, density_of_states = self.calculate_density_of_states(k=k)
|
468
523
|
|
469
|
-
coherence_peaks = np.where(
|
524
|
+
coherence_peaks = np.where(
|
525
|
+
np.isclose(density_of_states, np.max(density_of_states), rtol=1e-2)
|
526
|
+
)[0]
|
470
527
|
|
471
|
-
gap_region = density_of_states[coherence_peaks[0] : coherence_peaks[1] + 1] / np.max(
|
528
|
+
gap_region = density_of_states[coherence_peaks[0] : coherence_peaks[-1] + 1] / np.max(
|
472
529
|
density_of_states
|
473
530
|
)
|
474
|
-
energies_gap_region = energies[coherence_peaks[0] : coherence_peaks[1] + 1]
|
475
|
-
zero_indeces = np.where(gap_region <= 1e-
|
531
|
+
energies_gap_region = energies[coherence_peaks[0] : coherence_peaks[-1] + 1]
|
532
|
+
zero_indeces = np.where(gap_region <= 1e-6)[0]
|
476
533
|
if len(zero_indeces) == 0:
|
477
534
|
gap = 0
|
478
535
|
else:
|
@@ -482,16 +539,86 @@ class BaseHamiltonian(Generic[GenericParameters], ABC):
|
|
482
539
|
|
483
540
|
return gap
|
484
541
|
|
542
|
+
def calculate_free_energy(self, k: npt.NDArray[np.floating]) -> float:
|
543
|
+
"""Calculate the free energy for the Hamiltonian.
|
485
544
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
545
|
+
Parameters
|
546
|
+
----------
|
547
|
+
k
|
548
|
+
|
549
|
+
Returns
|
550
|
+
-------
|
551
|
+
free_energy
|
552
|
+
|
553
|
+
"""
|
554
|
+
number_k_points = len(k)
|
555
|
+
bdg_energies, _ = self.diagonalize_bdg(k)
|
556
|
+
integral: float = 0
|
557
|
+
|
558
|
+
k_array = (
|
559
|
+
1
|
560
|
+
/ self.beta
|
561
|
+
* np.array(
|
562
|
+
[
|
563
|
+
np.sum(np.log(1 + np.exp(-self.beta * bdg_energies[k_index])))
|
564
|
+
for k_index in range(number_k_points)
|
565
|
+
]
|
566
|
+
)
|
567
|
+
)
|
568
|
+
|
569
|
+
integral += -np.sum(k_array, axis=-1) / number_k_points + 0.5 * np.sum(
|
570
|
+
np.power(np.abs(self.delta_orbital_basis), 2) / self.hubbard_int_orbital_basis
|
571
|
+
)
|
491
572
|
|
573
|
+
return integral
|
492
574
|
|
493
|
-
def
|
494
|
-
|
495
|
-
|
575
|
+
def calculate_current_density(self, k: npt.NDArray[np.floating]) -> npt.NDArray[np.floating]:
|
576
|
+
"""Calculate the current density.
|
577
|
+
|
578
|
+
Parameters
|
579
|
+
----------
|
580
|
+
k
|
581
|
+
|
582
|
+
Returns
|
583
|
+
-------
|
584
|
+
current_density
|
585
|
+
|
586
|
+
"""
|
587
|
+
bdg_energies, bdg_wavefunctions = self.diagonalize_bdg(k=k)
|
588
|
+
h_der_x = self.hamiltonian_derivative(k=k, direction="x")
|
589
|
+
h_der_y = self.hamiltonian_derivative(k=k, direction="y")
|
590
|
+
|
591
|
+
current = np.zeros(2, dtype=np.complex128)
|
592
|
+
|
593
|
+
matrix_x = np.zeros((3, 3), dtype=np.complex128)
|
594
|
+
matrix_y = np.zeros((3, 3), dtype=np.complex128)
|
595
|
+
|
596
|
+
for k_index in range(len(k)):
|
597
|
+
for i in range(self.number_of_bands):
|
598
|
+
for j in range(self.number_of_bands):
|
599
|
+
for n in range(2 * self.number_of_bands):
|
600
|
+
matrix_x[i, j] += (
|
601
|
+
h_der_x[k_index, i, j]
|
602
|
+
* np.conjugate(bdg_wavefunctions[k_index, i, n])
|
603
|
+
* bdg_wavefunctions[k_index, j, n]
|
604
|
+
* fermi_dirac(bdg_energies[k_index, n].item(), self.beta)
|
605
|
+
)
|
606
|
+
matrix_y[i, j] *= (
|
607
|
+
h_der_y[k_index, i, j]
|
608
|
+
* np.conjugate(bdg_wavefunctions[k_index, i, n])
|
609
|
+
* bdg_wavefunctions[k_index, j, n]
|
610
|
+
* fermi_dirac(bdg_energies[k_index, n].item(), self.beta)
|
611
|
+
)
|
612
|
+
|
613
|
+
current[0] = np.sum(matrix_x, axis=None)
|
614
|
+
current[1] = np.sum(matrix_y, axis=None)
|
615
|
+
assert np.allclose(np.imag(current), 0, atol=1e-14)
|
616
|
+
|
617
|
+
return (2 * np.real(current)) / len(k)
|
618
|
+
|
619
|
+
|
620
|
+
def _gaussian(x: npt.NDArray[np.floating], sigma: float) -> npt.NDArray[np.floating]:
|
621
|
+
gaussian: npt.NDArray[np.floating] = np.exp(-(x**2) / (2 * sigma**2)) / np.sqrt(
|
622
|
+
2 * np.pi * sigma**2
|
496
623
|
)
|
497
|
-
return
|
624
|
+
return gaussian
|
@@ -26,7 +26,7 @@ class DressedGraphene(BaseHamiltonian[DressedGrapheneParameters]):
|
|
26
26
|
self.hubbard_int_orbital_basis = parameters.hubbard_int_orbital_basis
|
27
27
|
self.chemical_potential = parameters.chemical_potential
|
28
28
|
if parameters.delta is not None:
|
29
|
-
self.delta_orbital_basis =
|
29
|
+
self.delta_orbital_basis = parameters.delta.astype(np.complexfloating)
|
30
30
|
|
31
31
|
def setup_lattice(self, parameters: DressedGrapheneParameters) -> BaseLattice: # noqa: D102
|
32
32
|
return GrapheneLattice(lattice_constant=parameters.lattice_constant)
|
@@ -35,7 +35,7 @@ class DressedGraphene(BaseHamiltonian[DressedGrapheneParameters]):
|
|
35
35
|
def get_parameters_model(cls) -> type[DressedGrapheneParameters]: # noqa: D102
|
36
36
|
return DressedGrapheneParameters
|
37
37
|
|
38
|
-
def hamiltonian(self, k: npt.NDArray[np.
|
38
|
+
def hamiltonian(self, k: npt.NDArray[np.floating]) -> npt.NDArray[np.complexfloating]: # noqa: D102
|
39
39
|
assert _check_valid_array(k)
|
40
40
|
|
41
41
|
t_gr = self.hopping_gr
|
@@ -46,7 +46,7 @@ class DressedGraphene(BaseHamiltonian[DressedGrapheneParameters]):
|
|
46
46
|
if k.ndim == 1:
|
47
47
|
k = np.expand_dims(k, axis=0)
|
48
48
|
|
49
|
-
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.
|
49
|
+
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex128)
|
50
50
|
|
51
51
|
h[:, 0, 1] = -t_gr * (
|
52
52
|
np.exp(1j * k[:, 1] * a / np.sqrt(3))
|
@@ -73,8 +73,8 @@ class DressedGraphene(BaseHamiltonian[DressedGrapheneParameters]):
|
|
73
73
|
return h.squeeze()
|
74
74
|
|
75
75
|
def hamiltonian_derivative( # noqa: D102
|
76
|
-
self, k: npt.NDArray[np.
|
77
|
-
) -> npt.NDArray[np.
|
76
|
+
self, k: npt.NDArray[np.floating], direction: str
|
77
|
+
) -> npt.NDArray[np.complexfloating]:
|
78
78
|
assert _check_valid_array(k)
|
79
79
|
assert direction in ["x", "y"]
|
80
80
|
|
@@ -84,7 +84,7 @@ class DressedGraphene(BaseHamiltonian[DressedGrapheneParameters]):
|
|
84
84
|
if k.ndim == 1:
|
85
85
|
k = np.expand_dims(k, axis=0)
|
86
86
|
|
87
|
-
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.
|
87
|
+
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex128)
|
88
88
|
|
89
89
|
if direction == "x":
|
90
90
|
h[:, 0, 1] = (
|
@@ -25,7 +25,7 @@ class Graphene(BaseHamiltonian[GrapheneParameters]):
|
|
25
25
|
self.hopping = parameters.hopping
|
26
26
|
self.chemical_potential = parameters.chemical_potential
|
27
27
|
if parameters.delta is not None:
|
28
|
-
self.delta_orbital_basis =
|
28
|
+
self.delta_orbital_basis = parameters.delta.astype(np.complex128)
|
29
29
|
|
30
30
|
def setup_lattice(self, parameters: GrapheneParameters) -> GrapheneLattice: # noqa: D102
|
31
31
|
return GrapheneLattice(lattice_constant=parameters.lattice_constant)
|
@@ -34,7 +34,7 @@ class Graphene(BaseHamiltonian[GrapheneParameters]):
|
|
34
34
|
def get_parameters_model(cls) -> type[GrapheneParameters]: # noqa: D102
|
35
35
|
return GrapheneParameters
|
36
36
|
|
37
|
-
def hamiltonian(self, k: npt.NDArray[np.
|
37
|
+
def hamiltonian(self, k: npt.NDArray[np.floating]) -> npt.NDArray[np.complexfloating]: # noqa: D102
|
38
38
|
assert _check_valid_array(k)
|
39
39
|
hopping = self.hopping
|
40
40
|
lattice_constant = self.lattice.lattice_constant
|
@@ -42,7 +42,7 @@ class Graphene(BaseHamiltonian[GrapheneParameters]):
|
|
42
42
|
if k.ndim == 1:
|
43
43
|
k = np.expand_dims(k, axis=0)
|
44
44
|
|
45
|
-
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.
|
45
|
+
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex128)
|
46
46
|
|
47
47
|
h[:, 0, 1] = -hopping * (
|
48
48
|
np.exp(1j * k[:, 1] * lattice_constant / np.sqrt(3))
|
@@ -57,8 +57,8 @@ class Graphene(BaseHamiltonian[GrapheneParameters]):
|
|
57
57
|
return h.squeeze()
|
58
58
|
|
59
59
|
def hamiltonian_derivative( # noqa: D102
|
60
|
-
self, k: npt.NDArray[np.
|
61
|
-
) -> npt.NDArray[np.
|
60
|
+
self, k: npt.NDArray[np.floating], direction: str
|
61
|
+
) -> npt.NDArray[np.complexfloating]:
|
62
62
|
assert _check_valid_array(k)
|
63
63
|
assert direction in ["x", "y"]
|
64
64
|
|
@@ -67,7 +67,7 @@ class Graphene(BaseHamiltonian[GrapheneParameters]):
|
|
67
67
|
if k.ndim == 1:
|
68
68
|
k = np.expand_dims(k, axis=0)
|
69
69
|
|
70
|
-
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.
|
70
|
+
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex128)
|
71
71
|
|
72
72
|
if direction == "x":
|
73
73
|
h[:, 0, 1] = (
|
@@ -22,7 +22,7 @@ class OneBand(BaseHamiltonian[OneBandParameters]):
|
|
22
22
|
self.hopping = parameters.hopping
|
23
23
|
self.chemical_potential = parameters.chemical_potential
|
24
24
|
if parameters.delta is not None:
|
25
|
-
self.delta_orbital_basis =
|
25
|
+
self.delta_orbital_basis = parameters.delta.astype(np.complex128)
|
26
26
|
|
27
27
|
def setup_lattice(self, parameters: OneBandParameters) -> SquareLattice: # noqa: D102
|
28
28
|
return SquareLattice(lattice_constant=parameters.lattice_constant)
|
@@ -31,7 +31,7 @@ class OneBand(BaseHamiltonian[OneBandParameters]):
|
|
31
31
|
def get_parameters_model(cls) -> type[OneBandParameters]: # noqa: D102
|
32
32
|
return OneBandParameters
|
33
33
|
|
34
|
-
def hamiltonian(self, k: npt.NDArray[np.
|
34
|
+
def hamiltonian(self, k: npt.NDArray[np.floating]) -> npt.NDArray[np.complexfloating]: # noqa: D102
|
35
35
|
assert _check_valid_array(k)
|
36
36
|
hopping = self.hopping
|
37
37
|
lattice_constant = self.lattice.lattice_constant
|
@@ -39,7 +39,7 @@ class OneBand(BaseHamiltonian[OneBandParameters]):
|
|
39
39
|
if k.ndim == 1:
|
40
40
|
k = np.expand_dims(k, axis=0)
|
41
41
|
|
42
|
-
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.
|
42
|
+
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex128)
|
43
43
|
|
44
44
|
h[:, 0, 0] = (
|
45
45
|
-2 * hopping * (np.cos(k[:, 1] * lattice_constant) + np.cos(k[:, 0] * lattice_constant))
|
@@ -49,8 +49,8 @@ class OneBand(BaseHamiltonian[OneBandParameters]):
|
|
49
49
|
return h
|
50
50
|
|
51
51
|
def hamiltonian_derivative( # noqa: D102
|
52
|
-
self, k: npt.NDArray[np.
|
53
|
-
) -> npt.NDArray[np.
|
52
|
+
self, k: npt.NDArray[np.floating], direction: str
|
53
|
+
) -> npt.NDArray[np.complexfloating]:
|
54
54
|
assert _check_valid_array(k)
|
55
55
|
assert direction in ["x", "y"]
|
56
56
|
|
@@ -59,7 +59,7 @@ class OneBand(BaseHamiltonian[OneBandParameters]):
|
|
59
59
|
if k.ndim == 1:
|
60
60
|
k = np.expand_dims(k, axis=0)
|
61
61
|
|
62
|
-
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.
|
62
|
+
h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex128)
|
63
63
|
|
64
64
|
if direction == "x":
|
65
65
|
h[:, 0, 0] = -2 * hopping * lattice_constant * np.sin(lattice_constant * k[:, 0])
|