quant-met 0.0.7__py3-none-any.whl → 0.0.9__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/cli/__init__.py +22 -0
- quant_met/cli/main.py +34 -0
- quant_met/cli/scf.py +40 -0
- quant_met/geometry/__init__.py +12 -3
- quant_met/geometry/base_lattice.py +18 -4
- quant_met/geometry/graphene.py +11 -3
- quant_met/geometry/square.py +11 -3
- quant_met/mean_field/__init__.py +9 -32
- quant_met/mean_field/_utils.py +0 -11
- quant_met/mean_field/hamiltonians/__init__.py +31 -0
- quant_met/mean_field/{base_hamiltonian.py → hamiltonians/base_hamiltonian.py} +88 -77
- quant_met/mean_field/{eg_x.py → hamiltonians/dressed_graphene.py} +26 -58
- quant_met/mean_field/{graphene.py → hamiltonians/graphene.py} +20 -45
- quant_met/mean_field/{one_band_tight_binding.py → hamiltonians/one_band_tight_binding.py} +20 -48
- quant_met/mean_field/hamiltonians/three_band_tight_binding.py +116 -0
- quant_met/mean_field/hamiltonians/two_band_tight_binding.py +107 -0
- quant_met/mean_field/quantum_metric.py +4 -3
- quant_met/mean_field/self_consistency.py +15 -14
- quant_met/mean_field/superfluid_weight.py +7 -4
- quant_met/parameters/__init__.py +36 -0
- quant_met/parameters/hamiltonians.py +147 -0
- quant_met/parameters/main.py +37 -0
- quant_met/utils.py +1 -1
- {quant_met-0.0.7.dist-info → quant_met-0.0.9.dist-info}/METADATA +5 -3
- quant_met-0.0.9.dist-info/RECORD +33 -0
- quant_met-0.0.9.dist-info/entry_points.txt +3 -0
- quant_met/mean_field/free_energy.py +0 -130
- quant_met-0.0.7.dist-info/RECORD +0 -24
- {quant_met-0.0.7.dist-info → quant_met-0.0.9.dist-info}/LICENSE.txt +0 -0
- {quant_met-0.0.7.dist-info → quant_met-0.0.9.dist-info}/LICENSES/MIT.txt +0 -0
- {quant_met-0.0.7.dist-info → quant_met-0.0.9.dist-info}/WHEEL +0 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""
|
6
|
+
Command-Line-Interface (:mod:`quant_met.cli`)
|
7
|
+
=============================================
|
8
|
+
|
9
|
+
Functions
|
10
|
+
---------
|
11
|
+
|
12
|
+
.. autosummary::
|
13
|
+
:toctree: generated/
|
14
|
+
|
15
|
+
cli
|
16
|
+
""" # noqa: D205, D400
|
17
|
+
|
18
|
+
from .main import cli
|
19
|
+
|
20
|
+
__all__ = [
|
21
|
+
"cli",
|
22
|
+
]
|
quant_met/cli/main.py
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Command line interface."""
|
6
|
+
|
7
|
+
import sys
|
8
|
+
from typing import TextIO
|
9
|
+
|
10
|
+
import click
|
11
|
+
import yaml
|
12
|
+
|
13
|
+
from quant_met.parameters import Parameters
|
14
|
+
|
15
|
+
from .scf import scf
|
16
|
+
|
17
|
+
|
18
|
+
@click.command()
|
19
|
+
@click.argument("input-file", type=click.File("r"))
|
20
|
+
def cli(input_file: TextIO) -> None:
|
21
|
+
"""Command line interface for quant-met.
|
22
|
+
|
23
|
+
Parameters
|
24
|
+
----------
|
25
|
+
input_file
|
26
|
+
"""
|
27
|
+
params = Parameters(**yaml.safe_load(input_file))
|
28
|
+
|
29
|
+
match params.control.calculation:
|
30
|
+
case "scf":
|
31
|
+
scf(params)
|
32
|
+
case _:
|
33
|
+
print(f"Calculation {params.control.calculation} not found.")
|
34
|
+
sys.exit(1)
|
quant_met/cli/scf.py
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""Functions to run self-consistent calculation for the order parameter."""
|
6
|
+
|
7
|
+
from pathlib import Path
|
8
|
+
|
9
|
+
from quant_met import mean_field
|
10
|
+
from quant_met.mean_field.hamiltonians import BaseHamiltonian
|
11
|
+
from quant_met.parameters import Parameters
|
12
|
+
from quant_met.parameters.hamiltonians import HamiltonianParameters
|
13
|
+
|
14
|
+
|
15
|
+
def _hamiltonian_factory(
|
16
|
+
classname: str, parameters: HamiltonianParameters
|
17
|
+
) -> BaseHamiltonian[HamiltonianParameters]:
|
18
|
+
"""Create a hamiltonian by its class name."""
|
19
|
+
from quant_met.mean_field import hamiltonians
|
20
|
+
|
21
|
+
cls = getattr(hamiltonians, classname)
|
22
|
+
h: BaseHamiltonian[HamiltonianParameters] = cls(parameters)
|
23
|
+
return h
|
24
|
+
|
25
|
+
|
26
|
+
def scf(parameters: Parameters) -> None:
|
27
|
+
"""Self-consistent calculation for the order parameter."""
|
28
|
+
result_path = Path(parameters.control.outdir)
|
29
|
+
result_path.mkdir(exist_ok=True, parents=True)
|
30
|
+
h = _hamiltonian_factory(parameters=parameters.model, classname=parameters.model.name)
|
31
|
+
solved_h = mean_field.self_consistency_loop(
|
32
|
+
h=h,
|
33
|
+
k_space_grid=h.lattice.generate_bz_grid(
|
34
|
+
ncols=parameters.k_points.nk1, nrows=parameters.k_points.nk2
|
35
|
+
),
|
36
|
+
epsilon=parameters.control.conv_treshold,
|
37
|
+
)
|
38
|
+
print(solved_h.delta_orbital_basis)
|
39
|
+
result_file = result_path / f"{parameters.control.prefix}.hdf5"
|
40
|
+
solved_h.save(filename=result_file)
|
quant_met/geometry/__init__.py
CHANGED
@@ -15,12 +15,21 @@ Functions
|
|
15
15
|
:toctree: generated/
|
16
16
|
|
17
17
|
generate_bz_path
|
18
|
-
|
18
|
+
|
19
|
+
Classes
|
20
|
+
-------
|
21
|
+
|
22
|
+
.. autosummary::
|
23
|
+
:toctree: generated/
|
24
|
+
|
25
|
+
BaseLattice
|
26
|
+
GrapheneLattice
|
27
|
+
SquareLattice
|
19
28
|
""" # noqa: D205, D400
|
20
29
|
|
21
30
|
from .base_lattice import BaseLattice
|
22
31
|
from .bz_path import generate_bz_path
|
23
|
-
from .graphene import
|
32
|
+
from .graphene import GrapheneLattice
|
24
33
|
from .square import SquareLattice
|
25
34
|
|
26
|
-
__all__ = ["generate_bz_path", "BaseLattice", "
|
35
|
+
__all__ = ["generate_bz_path", "BaseLattice", "GrapheneLattice", "SquareLattice"]
|
@@ -19,19 +19,29 @@ class BaseLattice(ABC):
|
|
19
19
|
|
20
20
|
@property
|
21
21
|
@abstractmethod
|
22
|
-
def lattice_constant(self) ->
|
22
|
+
def lattice_constant(self) -> float: # pragma: no cover
|
23
23
|
"""Lattice constant."""
|
24
24
|
raise NotImplementedError
|
25
25
|
|
26
26
|
@property
|
27
27
|
@abstractmethod
|
28
|
-
def bz_corners(self) -> npt.NDArray[np.float64]:
|
28
|
+
def bz_corners(self) -> npt.NDArray[np.float64]: # pragma: no cover
|
29
29
|
"""Corners of the BZ."""
|
30
30
|
raise NotImplementedError
|
31
31
|
|
32
32
|
@property
|
33
33
|
@abstractmethod
|
34
|
-
def
|
34
|
+
def reciprocal_basis(
|
35
|
+
self,
|
36
|
+
) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]: # pragma: no cover
|
37
|
+
"""Reciprocal basis vectors."""
|
38
|
+
raise NotImplementedError
|
39
|
+
|
40
|
+
@property
|
41
|
+
@abstractmethod
|
42
|
+
def high_symmetry_points(
|
43
|
+
self,
|
44
|
+
) -> tuple[tuple[npt.NDArray[np.float64], str], ...]: # pragma: no cover
|
35
45
|
"""Tuple of high symmetry points and names."""
|
36
46
|
raise NotImplementedError
|
37
47
|
|
@@ -52,7 +62,11 @@ class BaseLattice(ABC):
|
|
52
62
|
|
53
63
|
"""
|
54
64
|
return generate_uniform_grid(
|
55
|
-
ncols,
|
65
|
+
ncols,
|
66
|
+
nrows,
|
67
|
+
self.reciprocal_basis[0],
|
68
|
+
self.reciprocal_basis[1],
|
69
|
+
origin=np.array([0, 0]),
|
56
70
|
)
|
57
71
|
|
58
72
|
def generate_high_symmetry_path(
|
quant_met/geometry/graphene.py
CHANGED
@@ -10,10 +10,10 @@ import numpy.typing as npt
|
|
10
10
|
from .base_lattice import BaseLattice
|
11
11
|
|
12
12
|
|
13
|
-
class
|
13
|
+
class GrapheneLattice(BaseLattice):
|
14
14
|
"""Lattice geometry for Graphene."""
|
15
15
|
|
16
|
-
def __init__(self, lattice_constant:
|
16
|
+
def __init__(self, lattice_constant: float) -> None:
|
17
17
|
self._lattice_constant = lattice_constant
|
18
18
|
self._bz_corners = (
|
19
19
|
4
|
@@ -25,15 +25,23 @@ class Graphene(BaseLattice):
|
|
25
25
|
self.M = np.pi / self.lattice_constant * np.array([1, 1 / np.sqrt(3)])
|
26
26
|
self.K = 4 * np.pi / (3 * self.lattice_constant) * np.array([1, 0])
|
27
27
|
self._high_symmetry_points = ((self.M, "M"), (self.Gamma, r"\Gamma"), (self.K, "K"))
|
28
|
+
self._reciprocal_basis = (
|
29
|
+
2 * np.pi / self.lattice_constant * np.array([1, 1 / np.sqrt(3)]),
|
30
|
+
2 * np.pi / self.lattice_constant * np.array([1, -1 / np.sqrt(3)]),
|
31
|
+
)
|
28
32
|
|
29
33
|
@property
|
30
|
-
def lattice_constant(self) ->
|
34
|
+
def lattice_constant(self) -> float: # noqa: D102
|
31
35
|
return self._lattice_constant
|
32
36
|
|
33
37
|
@property
|
34
38
|
def bz_corners(self) -> npt.NDArray[np.float64]: # noqa: D102
|
35
39
|
return self._bz_corners
|
36
40
|
|
41
|
+
@property
|
42
|
+
def reciprocal_basis(self) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]: # noqa: D102
|
43
|
+
return self._reciprocal_basis
|
44
|
+
|
37
45
|
@property
|
38
46
|
def high_symmetry_points(self) -> tuple[tuple[npt.NDArray[np.float64], str], ...]: # noqa: D102
|
39
47
|
return self._high_symmetry_points
|
quant_met/geometry/square.py
CHANGED
@@ -13,26 +13,34 @@ from .base_lattice import BaseLattice
|
|
13
13
|
class SquareLattice(BaseLattice):
|
14
14
|
"""Lattice geometry for Square Lattice."""
|
15
15
|
|
16
|
-
def __init__(self, lattice_constant:
|
16
|
+
def __init__(self, lattice_constant: float) -> None:
|
17
17
|
self._lattice_constant = lattice_constant
|
18
18
|
self._bz_corners = (
|
19
19
|
np.pi
|
20
20
|
/ lattice_constant
|
21
21
|
* np.array([np.array([1, 1]), np.array([-1, 1]), np.array([1, -1]), np.array([-1, -1])])
|
22
22
|
)
|
23
|
+
self._reciprocal_basis = (
|
24
|
+
2 * np.pi / self.lattice_constant * np.array([1, 0]),
|
25
|
+
2 * np.pi / self.lattice_constant * np.array([0, 1]),
|
26
|
+
)
|
23
27
|
self.Gamma = np.array([0, 0])
|
24
28
|
self.M = np.pi / lattice_constant * np.array([1, 1])
|
25
29
|
self.X = np.pi / lattice_constant * np.array([1, 0])
|
26
30
|
self._high_symmetry_points = ((self.Gamma, r"\Gamma"), (self.M, "M"))
|
27
31
|
|
28
32
|
@property
|
29
|
-
def lattice_constant(self) ->
|
33
|
+
def lattice_constant(self) -> float: # noqa: D102
|
30
34
|
return self._lattice_constant
|
31
35
|
|
32
36
|
@property
|
33
|
-
def bz_corners(self) -> npt.NDArray[np.float64]: # noqa: D102
|
37
|
+
def bz_corners(self) -> npt.NDArray[np.float64]: # noqa: D102 # pragma: no cover
|
34
38
|
return self._bz_corners
|
35
39
|
|
40
|
+
@property
|
41
|
+
def reciprocal_basis(self) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]: # noqa: D102
|
42
|
+
return self._reciprocal_basis
|
43
|
+
|
36
44
|
@property
|
37
45
|
def high_symmetry_points(self) -> tuple[tuple[npt.NDArray[np.float64], str], ...]: # noqa: D102
|
38
46
|
return self._high_symmetry_points
|
quant_met/mean_field/__init__.py
CHANGED
@@ -6,21 +6,13 @@
|
|
6
6
|
Mean field treatment (:mod:`quant_met.mean_field`)
|
7
7
|
==================================================
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
Base
|
9
|
+
Submodules
|
10
|
+
----------
|
13
11
|
|
14
12
|
.. autosummary::
|
15
|
-
|
13
|
+
:toctree: generated/
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
.. autosummary::
|
20
|
-
:toctree: generated/
|
21
|
-
|
22
|
-
GrapheneHamiltonian
|
23
|
-
EGXHamiltonian
|
15
|
+
hamiltonians
|
24
16
|
|
25
17
|
|
26
18
|
Functions
|
@@ -31,20 +23,12 @@ Functions
|
|
31
23
|
|
32
24
|
superfluid_weight
|
33
25
|
quantum_metric
|
34
|
-
|
35
|
-
|
26
|
+
quantum_metric_bdg
|
27
|
+
self_consistency_loop
|
36
28
|
""" # noqa: D205, D400
|
37
29
|
|
38
|
-
from .
|
39
|
-
|
40
|
-
from .free_energy import (
|
41
|
-
free_energy,
|
42
|
-
free_energy_complex_gap,
|
43
|
-
free_energy_real_gap,
|
44
|
-
free_energy_uniform_pairing,
|
45
|
-
)
|
46
|
-
from .graphene import GrapheneHamiltonian
|
47
|
-
from .one_band_tight_binding import OneBandTightBindingHamiltonian
|
30
|
+
from quant_met.mean_field import hamiltonians
|
31
|
+
|
48
32
|
from .quantum_metric import quantum_metric, quantum_metric_bdg
|
49
33
|
from .self_consistency import self_consistency_loop
|
50
34
|
from .superfluid_weight import superfluid_weight
|
@@ -53,13 +37,6 @@ __all__ = [
|
|
53
37
|
"superfluid_weight",
|
54
38
|
"quantum_metric",
|
55
39
|
"quantum_metric_bdg",
|
56
|
-
"free_energy",
|
57
|
-
"free_energy_complex_gap",
|
58
|
-
"free_energy_real_gap",
|
59
|
-
"free_energy_uniform_pairing",
|
60
40
|
"self_consistency_loop",
|
61
|
-
"
|
62
|
-
"GrapheneHamiltonian",
|
63
|
-
"EGXHamiltonian",
|
64
|
-
"OneBandTightBindingHamiltonian",
|
41
|
+
"hamiltonians",
|
65
42
|
]
|
quant_met/mean_field/_utils.py
CHANGED
@@ -14,14 +14,3 @@ def _check_valid_array(array_in: npt.NDArray[Any]) -> bool:
|
|
14
14
|
raise ValueError(msg)
|
15
15
|
|
16
16
|
return True
|
17
|
-
|
18
|
-
|
19
|
-
def _validate_float(float_in: float, parameter_name: str) -> float:
|
20
|
-
if np.isinf(float_in):
|
21
|
-
msg = f"{parameter_name} must not be Infinity"
|
22
|
-
raise ValueError(msg)
|
23
|
-
if np.isnan(float_in):
|
24
|
-
msg = f"{parameter_name} must not be NaN"
|
25
|
-
raise ValueError(msg)
|
26
|
-
|
27
|
-
return float_in
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 Tjark Sievers
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
|
5
|
+
"""
|
6
|
+
Hamiltonians (:mod:`quant_met.mean_field.hamiltonians`)
|
7
|
+
=======================================================
|
8
|
+
|
9
|
+
Base
|
10
|
+
|
11
|
+
.. autosummary::
|
12
|
+
:toctree: hamiltonians/
|
13
|
+
|
14
|
+
BaseHamiltonian
|
15
|
+
|
16
|
+
.. autosummary::
|
17
|
+
:toctree: hamiltonians/
|
18
|
+
|
19
|
+
Graphene
|
20
|
+
DressedGraphene
|
21
|
+
OneBand
|
22
|
+
""" # noqa: D205, D400
|
23
|
+
|
24
|
+
from .base_hamiltonian import BaseHamiltonian
|
25
|
+
from .dressed_graphene import DressedGraphene
|
26
|
+
from .graphene import Graphene
|
27
|
+
from .one_band_tight_binding import OneBand
|
28
|
+
from .three_band_tight_binding import ThreeBand
|
29
|
+
from .two_band_tight_binding import TwoBand
|
30
|
+
|
31
|
+
__all__ = ["BaseHamiltonian", "Graphene", "DressedGraphene", "OneBand", "TwoBand", "ThreeBand"]
|
@@ -6,55 +6,44 @@
|
|
6
6
|
|
7
7
|
import pathlib
|
8
8
|
from abc import ABC, abstractmethod
|
9
|
+
from typing import Generic
|
9
10
|
|
10
11
|
import h5py
|
11
12
|
import numpy as np
|
12
13
|
import numpy.typing as npt
|
13
14
|
import pandas as pd
|
14
15
|
|
15
|
-
from .
|
16
|
+
from quant_met.geometry import BaseLattice
|
17
|
+
from quant_met.mean_field._utils import _check_valid_array
|
18
|
+
from quant_met.parameters.hamiltonians import GenericParameters
|
16
19
|
|
17
20
|
|
18
|
-
class BaseHamiltonian(ABC):
|
21
|
+
class BaseHamiltonian(Generic[GenericParameters], ABC):
|
19
22
|
"""Base class for Hamiltonians."""
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
raise NotImplementedError
|
26
|
-
|
27
|
-
@property
|
28
|
-
def hubbard_int_orbital_basis(self) -> npt.NDArray[np.float64]:
|
29
|
-
"""
|
30
|
-
hubbard_int interaction split up in orbitals.
|
31
|
-
|
32
|
-
Returns
|
33
|
-
-------
|
34
|
-
:class:`numpy.ndarray`
|
24
|
+
def __init__(self, parameters: GenericParameters) -> None:
|
25
|
+
self.name = parameters.name
|
26
|
+
self.beta = parameters.beta if parameters.beta else 1000.0
|
27
|
+
self.q = parameters.q if parameters.q is not None else np.zeros(2)
|
35
28
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def delta_orbital_basis(self) -> npt.NDArray[np.complex64]:
|
41
|
-
"""
|
42
|
-
Order parameter in orbital basis.
|
43
|
-
|
44
|
-
Returns
|
45
|
-
-------
|
46
|
-
:class:`numpy.ndarray`
|
29
|
+
self.lattice = self.setup_lattice(parameters)
|
30
|
+
self.hubbard_int_orbital_basis = parameters.hubbard_int_orbital_basis
|
31
|
+
self.number_of_bands = len(self.hubbard_int_orbital_basis)
|
32
|
+
self.delta_orbital_basis = np.zeros(self.number_of_bands, dtype=np.complex64)
|
47
33
|
|
48
|
-
|
49
|
-
|
34
|
+
@abstractmethod
|
35
|
+
def setup_lattice(self, parameters: GenericParameters) -> BaseLattice: # pragma: no cover
|
36
|
+
"""Set up lattice based on parameters."""
|
50
37
|
|
51
|
-
@
|
38
|
+
@classmethod
|
52
39
|
@abstractmethod
|
53
|
-
def
|
54
|
-
|
40
|
+
def get_parameters_model(cls) -> type[GenericParameters]: # pragma: no cover
|
41
|
+
"""Return the specific parameters model for the subclass."""
|
55
42
|
|
56
43
|
@abstractmethod
|
57
|
-
def hamiltonian(
|
44
|
+
def hamiltonian(
|
45
|
+
self, k: npt.NDArray[np.float64]
|
46
|
+
) -> npt.NDArray[np.complex64]: # pragma: no cover
|
58
47
|
"""
|
59
48
|
Return the normal state Hamiltonian in orbital basis.
|
60
49
|
|
@@ -69,12 +58,11 @@ class BaseHamiltonian(ABC):
|
|
69
58
|
Hamiltonian in matrix form.
|
70
59
|
|
71
60
|
"""
|
72
|
-
raise NotImplementedError
|
73
61
|
|
74
62
|
@abstractmethod
|
75
63
|
def hamiltonian_derivative(
|
76
64
|
self, k: npt.NDArray[np.float64], direction: str
|
77
|
-
) -> npt.NDArray[np.complex64]:
|
65
|
+
) -> npt.NDArray[np.complex64]: # pragma: no cover
|
78
66
|
"""
|
79
67
|
Deriative of the Hamiltonian.
|
80
68
|
|
@@ -91,7 +79,6 @@ class BaseHamiltonian(ABC):
|
|
91
79
|
Derivative of Hamiltonian.
|
92
80
|
|
93
81
|
"""
|
94
|
-
raise NotImplementedError
|
95
82
|
|
96
83
|
def save(self, filename: pathlib.Path) -> None:
|
97
84
|
"""
|
@@ -103,28 +90,23 @@ class BaseHamiltonian(ABC):
|
|
103
90
|
Filename to save the Hamiltonian to, should end in .hdf5
|
104
91
|
|
105
92
|
"""
|
106
|
-
with h5py.File(f"{filename}", "w") as f:
|
93
|
+
with h5py.File(f"{filename.absolute()}", "w") as f:
|
107
94
|
f.create_dataset("delta", data=self.delta_orbital_basis)
|
108
95
|
for key, value in vars(self).items():
|
109
|
-
if
|
110
|
-
f.attrs[key] = value
|
96
|
+
if key != "lattice":
|
97
|
+
f.attrs[key.strip("_")] = value
|
98
|
+
f.attrs["lattice_constant"] = self.lattice.lattice_constant
|
111
99
|
|
112
100
|
@classmethod
|
113
|
-
def from_file(cls, filename: pathlib.Path) -> "BaseHamiltonian":
|
114
|
-
"""
|
115
|
-
|
116
|
-
|
117
|
-
Parameters
|
118
|
-
----------
|
119
|
-
filename : :class:`pathlib.Path`
|
120
|
-
File to load the Hamiltonian from.
|
121
|
-
|
122
|
-
"""
|
123
|
-
with h5py.File(f"{filename}", "r") as f:
|
101
|
+
def from_file(cls, filename: pathlib.Path) -> "BaseHamiltonian[GenericParameters]":
|
102
|
+
"""Initialize a Hamiltonian from an HDF5 file."""
|
103
|
+
with h5py.File(str(filename), "r") as f:
|
124
104
|
config_dict = dict(f.attrs.items())
|
125
105
|
config_dict["delta"] = f["delta"][()]
|
126
106
|
|
127
|
-
|
107
|
+
parameters_model = cls.get_parameters_model()
|
108
|
+
parameters = parameters_model.model_validate(config_dict)
|
109
|
+
return cls(parameters=parameters)
|
128
110
|
|
129
111
|
def bdg_hamiltonian(self, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
|
130
112
|
"""
|
@@ -154,10 +136,11 @@ class BaseHamiltonian(ABC):
|
|
154
136
|
:,
|
155
137
|
self.number_of_bands : 2 * self.number_of_bands,
|
156
138
|
self.number_of_bands : 2 * self.number_of_bands,
|
157
|
-
] = -self.hamiltonian(-k).conjugate()
|
139
|
+
] = -self.hamiltonian(self.q - k).conjugate()
|
158
140
|
|
159
141
|
for i in range(self.number_of_bands):
|
160
142
|
h[:, self.number_of_bands + i, i] = self.delta_orbital_basis[i]
|
143
|
+
|
161
144
|
h[:, 0 : self.number_of_bands, self.number_of_bands : self.number_of_bands * 2] = (
|
162
145
|
h[:, self.number_of_bands : self.number_of_bands * 2, 0 : self.number_of_bands]
|
163
146
|
.copy()
|
@@ -240,7 +223,8 @@ class BaseHamiltonian(ABC):
|
|
240
223
|
return band_energies.squeeze(), bloch_wavefunctions.squeeze()
|
241
224
|
|
242
225
|
def diagonalize_bdg(
|
243
|
-
self,
|
226
|
+
self,
|
227
|
+
k: npt.NDArray[np.float64],
|
244
228
|
) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.complex64]]:
|
245
229
|
"""
|
246
230
|
Diagonalize the BdG Hamiltonian.
|
@@ -258,7 +242,7 @@ class BaseHamiltonian(ABC):
|
|
258
242
|
Diagonalising matrix of the BdG Hamiltonian.
|
259
243
|
|
260
244
|
"""
|
261
|
-
bdg_matrix = self.bdg_hamiltonian(k)
|
245
|
+
bdg_matrix = self.bdg_hamiltonian(k=k)
|
262
246
|
if bdg_matrix.ndim == 2:
|
263
247
|
bdg_matrix = np.expand_dims(bdg_matrix, axis=0)
|
264
248
|
k = np.expand_dims(k, axis=0)
|
@@ -275,13 +259,13 @@ class BaseHamiltonian(ABC):
|
|
275
259
|
return bdg_energies.squeeze(), bdg_wavefunctions.squeeze()
|
276
260
|
|
277
261
|
def gap_equation(
|
278
|
-
self,
|
262
|
+
self,
|
263
|
+
k: npt.NDArray[np.float64],
|
279
264
|
) -> npt.NDArray[np.complex64]:
|
280
265
|
"""Gap equation.
|
281
266
|
|
282
267
|
Parameters
|
283
268
|
----------
|
284
|
-
beta
|
285
269
|
k
|
286
270
|
|
287
271
|
Returns
|
@@ -291,28 +275,23 @@ class BaseHamiltonian(ABC):
|
|
291
275
|
|
292
276
|
|
293
277
|
"""
|
294
|
-
bdg_energies, bdg_wavefunctions = self.diagonalize_bdg(k)
|
295
|
-
bdg_energies_minus_k, _ = self.diagonalize_bdg(-k)
|
278
|
+
bdg_energies, bdg_wavefunctions = self.diagonalize_bdg(k=k)
|
296
279
|
delta = np.zeros(self.number_of_bands, dtype=np.complex64)
|
297
280
|
|
298
281
|
for i in range(self.number_of_bands):
|
299
282
|
sum_tmp = 0
|
300
|
-
for j in range(self.number_of_bands):
|
283
|
+
for j in range(2 * self.number_of_bands):
|
301
284
|
for k_index in range(len(k)):
|
302
|
-
sum_tmp +=
|
303
|
-
k_index, i
|
304
|
-
|
305
|
-
bdg_energies[k_index, j
|
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
|
285
|
+
sum_tmp += (
|
286
|
+
np.conjugate(bdg_wavefunctions[k_index, i, j])
|
287
|
+
* bdg_wavefunctions[k_index, i + self.number_of_bands, j]
|
288
|
+
* _fermi_dirac(bdg_energies[k_index, j].item(), self.beta)
|
312
289
|
)
|
313
290
|
delta[i] = (-self.hubbard_int_orbital_basis[i] * sum_tmp / len(k)).conjugate()
|
314
291
|
|
315
|
-
delta_without_phase: npt.NDArray[np.complex64] = delta * np.exp(
|
292
|
+
delta_without_phase: npt.NDArray[np.complex64] = delta * np.exp(
|
293
|
+
-1j * np.angle(delta[np.argmax(np.abs(delta))])
|
294
|
+
)
|
316
295
|
return delta_without_phase
|
317
296
|
|
318
297
|
def calculate_bandstructure(
|
@@ -358,27 +337,59 @@ class BaseHamiltonian(ABC):
|
|
358
337
|
return results
|
359
338
|
|
360
339
|
def calculate_density_of_states(
|
361
|
-
self,
|
362
|
-
|
340
|
+
self,
|
341
|
+
k: npt.NDArray[np.float64],
|
342
|
+
) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
|
363
343
|
"""Calculate the density of states.
|
364
344
|
|
365
345
|
Parameters
|
366
346
|
----------
|
367
347
|
k
|
368
|
-
energies
|
369
348
|
|
370
349
|
Returns
|
371
350
|
-------
|
372
351
|
Density of states.
|
373
352
|
|
374
353
|
"""
|
375
|
-
density_of_states = np.zeros(shape=energies.shape, dtype=np.float64)
|
376
354
|
bands, _ = self.diagonalize_bdg(k=k)
|
355
|
+
energies = np.linspace(start=np.min(bands), stop=np.max(bands), num=5000)
|
356
|
+
density_of_states = np.zeros(shape=energies.shape, dtype=np.float64)
|
357
|
+
|
377
358
|
for i, energy in enumerate(energies):
|
378
359
|
density_of_states[i] = np.sum(
|
379
360
|
_gaussian(x=(energy - bands.flatten()), sigma=1e-2)
|
380
361
|
) / len(k)
|
381
|
-
return density_of_states
|
362
|
+
return energies, density_of_states
|
363
|
+
|
364
|
+
def calculate_spectral_gap(self, k: npt.NDArray[np.float64]) -> float:
|
365
|
+
"""Calculate the spectral gap.
|
366
|
+
|
367
|
+
Parameters
|
368
|
+
----------
|
369
|
+
k
|
370
|
+
|
371
|
+
Returns
|
372
|
+
-------
|
373
|
+
Spectral gap
|
374
|
+
|
375
|
+
"""
|
376
|
+
energies, density_of_states = self.calculate_density_of_states(k=k)
|
377
|
+
|
378
|
+
coherence_peaks = np.where(np.isclose(density_of_states, np.max(density_of_states)))[0]
|
379
|
+
|
380
|
+
gap_region = density_of_states[coherence_peaks[0] : coherence_peaks[1] + 1] / np.max(
|
381
|
+
density_of_states
|
382
|
+
)
|
383
|
+
energies_gap_region = energies[coherence_peaks[0] : coherence_peaks[1] + 1]
|
384
|
+
zero_indeces = np.where(gap_region <= 1e-10)[0]
|
385
|
+
if len(zero_indeces) == 0:
|
386
|
+
gap = 0
|
387
|
+
else:
|
388
|
+
gap = (
|
389
|
+
energies_gap_region[zero_indeces[-1]] - energies_gap_region[zero_indeces[0]]
|
390
|
+
).item()
|
391
|
+
|
392
|
+
return gap
|
382
393
|
|
383
394
|
|
384
395
|
def _gaussian(x: npt.NDArray[np.float64], sigma: float) -> npt.NDArray[np.float64]:
|
@@ -388,6 +399,6 @@ def _gaussian(x: npt.NDArray[np.float64], sigma: float) -> npt.NDArray[np.float6
|
|
388
399
|
return gaussian
|
389
400
|
|
390
401
|
|
391
|
-
def _fermi_dirac(energy:
|
392
|
-
fermi_dirac:
|
402
|
+
def _fermi_dirac(energy: float, beta: float) -> float:
|
403
|
+
fermi_dirac: float = 1 / (1 + np.exp(beta * energy))
|
393
404
|
return fermi_dirac
|