quant-met 0.0.27__py3-none-any.whl → 0.1.1__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.
Files changed (47) hide show
  1. quant_met/__init__.py +2 -7
  2. quant_met/bdg/__init__.py +26 -0
  3. quant_met/bdg/bdg_hamiltonian.py +97 -0
  4. quant_met/bdg/gap_equation.py +127 -0
  5. quant_met/bdg/sc_current.py +60 -0
  6. quant_met/bdg/superfluid_weight.py +110 -0
  7. quant_met/cli/__init__.py +0 -5
  8. quant_met/cli/crit_temp.py +18 -16
  9. quant_met/cli/main.py +8 -5
  10. quant_met/cli/q_analysis.py +60 -0
  11. quant_met/cli/q_loop.py +95 -0
  12. quant_met/cli/scf.py +44 -23
  13. quant_met/parameters/__init__.py +0 -26
  14. quant_met/parameters/control.py +57 -0
  15. quant_met/parameters/main.py +2 -55
  16. quant_met/quantum_geometry/__init__.py +13 -0
  17. quant_met/quantum_geometry/qgt.py +37 -0
  18. quant_met/routines/__init__.py +22 -0
  19. quant_met/routines/analyse_q_data.py +226 -0
  20. quant_met/routines/loop_over_q.py +154 -0
  21. quant_met/{mean_field → routines}/search_crit_temp.py +71 -48
  22. quant_met/{mean_field → routines}/self_consistency.py +32 -28
  23. quant_met/utils.py +1 -6
  24. {quant_met-0.0.27.dist-info → quant_met-0.1.1.dist-info}/METADATA +5 -11
  25. quant_met-0.1.1.dist-info/RECORD +28 -0
  26. quant_met/cli/_utils.py +0 -32
  27. quant_met/geometry/__init__.py +0 -36
  28. quant_met/geometry/base_lattice.py +0 -100
  29. quant_met/geometry/bz_path.py +0 -90
  30. quant_met/geometry/graphene.py +0 -48
  31. quant_met/geometry/square.py +0 -47
  32. quant_met/mean_field/__init__.py +0 -38
  33. quant_met/mean_field/_utils.py +0 -17
  34. quant_met/mean_field/hamiltonians/__init__.py +0 -34
  35. quant_met/mean_field/hamiltonians/base_hamiltonian.py +0 -793
  36. quant_met/mean_field/hamiltonians/dressed_graphene.py +0 -118
  37. quant_met/mean_field/hamiltonians/graphene.py +0 -95
  38. quant_met/mean_field/hamiltonians/one_band_tight_binding.py +0 -70
  39. quant_met/mean_field/hamiltonians/three_band_tight_binding.py +0 -85
  40. quant_met/mean_field/hamiltonians/two_band_tight_binding.py +0 -76
  41. quant_met/parameters/hamiltonians.py +0 -182
  42. quant_met/plotting/__init__.py +0 -31
  43. quant_met/plotting/plotting.py +0 -215
  44. quant_met-0.0.27.dist-info/RECORD +0 -33
  45. {quant_met-0.0.27.dist-info → quant_met-0.1.1.dist-info}/WHEEL +0 -0
  46. {quant_met-0.0.27.dist-info → quant_met-0.1.1.dist-info}/entry_points.txt +0 -0
  47. {quant_met-0.0.27.dist-info → quant_met-0.1.1.dist-info}/licenses/LICENSE.txt +0 -0
quant_met/__init__.py CHANGED
@@ -1,10 +1,5 @@
1
- # SPDX-FileCopyrightText: 2024 Tjark Sievers
2
- # SPDX-FileCopyrightText: 2025 Tjark Sievers
3
- #
4
- # SPDX-License-Identifier: MIT
5
-
6
1
  """quant-met, a package to treat superconductivity in flat-band systems."""
7
2
 
8
- from . import cli, geometry, mean_field, parameters, plotting
3
+ from . import bdg, cli, quantum_geometry, routines
9
4
 
10
- __all__ = ["cli", "geometry", "mean_field", "parameters", "plotting"]
5
+ __all__ = ["bdg", "cli", "quantum_geometry", "routines"]
@@ -0,0 +1,26 @@
1
+ """
2
+ Bogoliubov-de Gennes (BdG)
3
+ ==========================
4
+
5
+ .. autosummary::
6
+ :toctree: generated/
7
+
8
+ bdg_hamiltonian
9
+ diagonalize_bdg
10
+ gap_equation
11
+ calculate_superfluid_weight
12
+ calculate_current_density
13
+ """ # noqa: D205, D400
14
+
15
+ from .bdg_hamiltonian import bdg_hamiltonian, diagonalize_bdg
16
+ from .gap_equation import gap_equation
17
+ from .sc_current import calculate_current_density
18
+ from .superfluid_weight import calculate_superfluid_weight
19
+
20
+ __all__ = [
21
+ "bdg_hamiltonian",
22
+ "calculate_current_density",
23
+ "calculate_superfluid_weight",
24
+ "diagonalize_bdg",
25
+ "gap_equation",
26
+ ]
@@ -0,0 +1,97 @@
1
+ """BdG Hamiltonian."""
2
+
3
+ import numpy as np
4
+ import numpy.typing as npt
5
+ import sisl
6
+
7
+
8
+ def bdg_hamiltonian(
9
+ hamiltonian: sisl.Hamiltonian,
10
+ k: npt.NDArray[np.floating],
11
+ delta_orbital_basis: npt.NDArray[np.complexfloating],
12
+ q: npt.NDArray[np.floating] | None = None,
13
+ ) -> npt.NDArray[np.complexfloating]:
14
+ """
15
+ Construct the BdG Hamiltonian at momentum k.
16
+
17
+ Parameters
18
+ ----------
19
+ hamiltonian : sisl.Hamiltonian
20
+ The normal-state tight-binding Hamiltonian.
21
+ k : np.ndarray
22
+ k-point(s) in reduced coordinates. Shape: (3,) or (N_k, 3).
23
+ delta_orbital_basis : np.ndarray
24
+ Pairing amplitudes in the orbital basis. Shape: (N_orbitals,)
25
+ q : np.ndarray, optional
26
+ Pairing momentum (e.g. for FFLO). Default is 0.
27
+
28
+ Returns
29
+ -------
30
+ np.ndarray
31
+ The BdG Hamiltonian. Shape: (2N, 2N) or (N_k, 2N, 2N)
32
+ """
33
+ k = np.atleast_2d(k)
34
+ n_k_points = k.shape[0]
35
+ n_orbitals = hamiltonian.no
36
+
37
+ if q is None:
38
+ q = np.zeros(3)
39
+
40
+ h_bdg = np.zeros((n_k_points, 2 * n_orbitals, 2 * n_orbitals), dtype=np.complex128)
41
+
42
+ for i, kpt in enumerate(k):
43
+ h_k = hamiltonian.Hk(kpt).toarray()
44
+ h_mkq = hamiltonian.Hk(q - kpt).toarray()
45
+
46
+ h_bdg[i, :n_orbitals, :n_orbitals] = h_k
47
+ h_bdg[i, n_orbitals:, n_orbitals:] = -h_mkq.conj()
48
+
49
+ for j in range(n_orbitals):
50
+ h_bdg[i, n_orbitals + j, j] = delta_orbital_basis[j]
51
+
52
+ h_bdg[i, :n_orbitals, n_orbitals:] = h_bdg[i, n_orbitals:, :n_orbitals].conj().T
53
+
54
+ return h_bdg.squeeze()
55
+
56
+
57
+ def diagonalize_bdg(
58
+ hamiltonian: sisl.Hamiltonian,
59
+ kgrid: sisl.MonkhorstPack,
60
+ delta_orbital_basis: np.ndarray,
61
+ q: npt.NDArray[np.floating] | None,
62
+ ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.complex128]]:
63
+ """Diagonalizes the BdG Hamiltonian.
64
+
65
+ This method computes the eigenvalues and eigenvectors of the Bogoliubov-de
66
+ Gennes Hamiltonian, providing insight into the quasiparticle excitations in
67
+ superconducting states.
68
+
69
+ Parameters
70
+ ----------
71
+ q
72
+ kgrid
73
+ delta_orbital_basis
74
+ hamiltonian
75
+
76
+ Returns
77
+ -------
78
+ tuple
79
+ - :class:`numpy.ndarray`: Eigenvalues of the BdG Hamiltonian.
80
+ - :class:`numpy.ndarray`: Eigenvectors corresponding to the eigenvalues of the
81
+ BdG Hamiltonian.
82
+ """
83
+ energies = []
84
+ wavefunctions = []
85
+
86
+ for kpt in kgrid:
87
+ bdg = bdg_hamiltonian(
88
+ hamiltonian=hamiltonian,
89
+ delta_orbital_basis=delta_orbital_basis,
90
+ k=kpt,
91
+ q=q,
92
+ )
93
+ e, v = np.linalg.eigh(bdg)
94
+ energies.append(e)
95
+ wavefunctions.append(v)
96
+
97
+ return np.array(energies), np.array(wavefunctions)
@@ -0,0 +1,127 @@
1
+ """Gap equation."""
2
+
3
+ import numpy as np
4
+ import numpy.typing as npt
5
+ import sisl
6
+ from numba import jit
7
+
8
+ from .bdg_hamiltonian import diagonalize_bdg
9
+
10
+
11
+ def gap_equation( # noqa: PLR0913
12
+ hamiltonian: sisl.Hamiltonian,
13
+ beta: float,
14
+ hubbard_int_orbital_basis: npt.NDArray[np.float64],
15
+ delta_orbital_basis: npt.NDArray[np.complex128],
16
+ kgrid: sisl.MonkhorstPack,
17
+ q: npt.NDArray[np.float64] | None,
18
+ ) -> npt.NDArray[np.complexfloating]:
19
+ """Gap equation.
20
+
21
+ Parameters
22
+ ----------
23
+ q
24
+ kgrid
25
+ delta_orbital_basis
26
+ hubbard_int_orbital_basis
27
+ beta
28
+ hamiltonian
29
+
30
+ Returns
31
+ -------
32
+ New delta
33
+ """
34
+ bdg_energies, bdg_wavefunctions = diagonalize_bdg(
35
+ hamiltonian=hamiltonian,
36
+ kgrid=kgrid,
37
+ q=q,
38
+ delta_orbital_basis=delta_orbital_basis,
39
+ )
40
+ delta = np.zeros(hamiltonian.no, dtype=np.complex128)
41
+ return gap_equation_loop(
42
+ bdg_energies=bdg_energies,
43
+ bdg_wavefunctions=bdg_wavefunctions,
44
+ delta=delta,
45
+ beta=beta,
46
+ hubbard_int_orbital_basis=hubbard_int_orbital_basis,
47
+ kgrid=kgrid.k,
48
+ weights=kgrid.weight,
49
+ )
50
+
51
+
52
+ @jit
53
+ def gap_equation_loop( # noqa: PLR0913
54
+ bdg_energies: npt.NDArray[np.float64],
55
+ bdg_wavefunctions: npt.NDArray[np.complex128],
56
+ delta: npt.NDArray[np.complex128],
57
+ beta: float,
58
+ hubbard_int_orbital_basis: npt.NDArray[np.float64],
59
+ kgrid: npt.NDArray[np.float64],
60
+ weights: npt.NDArray[np.float64],
61
+ ) -> npt.NDArray[np.complexfloating]:
62
+ """Calculate the gap equation.
63
+
64
+ The gap equation determines the order parameter for superconductivity by
65
+ relating the pairings to the spectral properties of the BdG Hamiltonian.
66
+
67
+ Parameters
68
+ ----------
69
+ kgrid
70
+ bdg_energies : :class:`numpy.ndarray`
71
+ BdG energies
72
+ bdg_wavefunctions : :class:`numpy.ndarray`
73
+ BdG wavefunctions
74
+ delta : :class:`numpy.ndarray`
75
+ Delta
76
+ beta : :class:`float`
77
+ Beta
78
+ hubbard_int_orbital_basis : :class:`numpy.ndarray`
79
+ Hubard interaction in orbital basis
80
+ k : :class:`numpy.ndarray`
81
+ List of k points in reciprocal space.
82
+
83
+ Returns
84
+ -------
85
+ :class:`numpy.ndarray`
86
+ New pairing gap in orbital basis, adjusted to remove global phase.
87
+ """
88
+ number_of_bands = len(delta)
89
+ new_delta = np.zeros_like(delta)
90
+
91
+ for i in range(number_of_bands):
92
+ sum_tmp = 0
93
+ for k_index in range(len(kgrid)):
94
+ weight = weights[k_index]
95
+
96
+ for j in range(2 * number_of_bands):
97
+ sum_tmp += (
98
+ np.conj(bdg_wavefunctions[k_index, i, j])
99
+ * bdg_wavefunctions[k_index, i + number_of_bands, j]
100
+ * fermi_dirac(bdg_energies[k_index, j], beta)
101
+ * weight
102
+ )
103
+ new_delta[i] = (-hubbard_int_orbital_basis[i] * sum_tmp).conjugate()
104
+
105
+ new_delta *= np.exp(-1j * np.angle(new_delta[np.argmax(np.abs(new_delta))]))
106
+ return new_delta
107
+
108
+
109
+ @jit
110
+ def fermi_dirac(energy: npt.NDArray[np.floating], beta: float) -> npt.NDArray[np.floating]:
111
+ """Fermi dirac distribution.
112
+
113
+ Parameters
114
+ ----------
115
+ energy
116
+ beta
117
+
118
+ Returns
119
+ -------
120
+ fermi_dirac
121
+
122
+ """
123
+ return (
124
+ np.where(energy < 0, 1.0, 0.0)
125
+ if np.isinf(beta)
126
+ else np.asarray(1 / (1 + np.exp(beta * energy)))
127
+ )
@@ -0,0 +1,60 @@
1
+ """Calculate supercurrent."""
2
+
3
+ import numpy as np
4
+ import sisl
5
+ from numpy.typing import NDArray
6
+
7
+
8
+ def calculate_current_density(
9
+ hamiltonian: sisl.Hamiltonian,
10
+ k: sisl.MonkhorstPack,
11
+ bdg_energies: NDArray[np.floating],
12
+ bdg_wavefunctions: NDArray[np.complexfloating],
13
+ beta: float,
14
+ ) -> NDArray[np.floating]:
15
+ """Calculate current density from BdG wavefunctions and normal-state Hamiltonian derivatives.
16
+
17
+ Parameters
18
+ ----------
19
+ hamiltonian : sisl.Hamiltonian
20
+ The normal-state Hamiltonian.
21
+ k : np.ndarray
22
+ Array of k-points in the Brillouin zone.
23
+ bdg_energies : np.ndarray
24
+ BdG eigenvalues for each k-point.
25
+ bdg_wavefunctions : np.ndarray
26
+ BdG eigenvectors for each k-point.
27
+ beta : float
28
+ Inverse temperature (1 / k_B T).
29
+
30
+ Returns
31
+ -------
32
+ np.ndarray
33
+ Real current density vector (2D).
34
+ """
35
+
36
+ def fermi_dirac(e: float, beta: float) -> float:
37
+ return 1.0 / (np.exp(beta * e) + 1)
38
+
39
+ num_bands = hamiltonian.no
40
+ current = np.zeros(2, dtype=np.complex128)
41
+
42
+ for dir_idx, _direction in enumerate(["x", "y"]):
43
+ matrix = np.zeros((num_bands, num_bands), dtype=np.complex128)
44
+
45
+ for k_index, kpt in enumerate(k):
46
+ dhk = hamiltonian.dHk(kpt, format="array")[dir_idx]
47
+
48
+ for i in range(num_bands):
49
+ for j in range(num_bands):
50
+ for n in range(2 * num_bands):
51
+ matrix[i, j] += (
52
+ dhk[i, j]
53
+ * np.conj(bdg_wavefunctions[k_index, i, n])
54
+ * bdg_wavefunctions[k_index, j, n]
55
+ * fermi_dirac(bdg_energies[k_index, n], beta)
56
+ )
57
+
58
+ current[dir_idx] = np.sum(matrix)
59
+
60
+ return (2 * np.real(current)) / len(k)
@@ -0,0 +1,110 @@
1
+ """Function to calculate superfluid weight."""
2
+
3
+ import numpy as np
4
+ import numpy.typing as npt
5
+ import sisl
6
+
7
+ from .bdg_hamiltonian import bdg_hamiltonian
8
+
9
+
10
+ def calculate_superfluid_weight(
11
+ hamiltonian: sisl.Hamiltonian,
12
+ kgrid: sisl.MonkhorstPack,
13
+ beta: float,
14
+ delta_orbital_basis: npt.NDArray[np.complexfloating],
15
+ ) -> tuple[npt.NDArray[np.complexfloating], npt.NDArray[np.complexfloating]]:
16
+ """Calculate superfluid weight (conventional + geometric)."""
17
+ s_weight_conv = np.zeros((2, 2), dtype=np.complex128)
18
+ s_weight_geom = np.zeros((2, 2), dtype=np.complex128)
19
+ c_mnpq_cache = {}
20
+
21
+ for i, _dir1 in enumerate(["x", "y"]):
22
+ for j, _dir2 in enumerate(["x", "y"]):
23
+ for k_point in kgrid:
24
+ k_tuple = tuple(k_point)
25
+
26
+ # Solve BdG problem
27
+ bdg_h = bdg_hamiltonian(hamiltonian, k_point, delta_orbital_basis)
28
+ energies, wavefuncs = np.linalg.eigh(bdg_h)
29
+
30
+ # Cache coefficient tensor
31
+ if k_tuple not in c_mnpq_cache:
32
+ c_mnpq_cache[k_tuple] = _c_factor(energies, wavefuncs, beta)
33
+ c_mnpq = c_mnpq_cache[k_tuple]
34
+
35
+ bdg_h_deriv_1 = np.zeros(
36
+ (2 * hamiltonian.no, 2 * hamiltonian.no),
37
+ dtype=np.complex128,
38
+ )
39
+ bdg_h_deriv_2 = np.zeros(
40
+ (2 * hamiltonian.no, 2 * hamiltonian.no),
41
+ dtype=np.complex128,
42
+ )
43
+
44
+ bdg_h_deriv_1[0 : hamiltonian.no, 0 : hamiltonian.no] = hamiltonian.dHk(
45
+ k=k_point,
46
+ format="array",
47
+ )[i]
48
+ bdg_h_deriv_1[
49
+ hamiltonian.no : 2 * hamiltonian.no,
50
+ hamiltonian.no : 2 * hamiltonian.no,
51
+ ] = hamiltonian.dHk(k=-k_point, format="array")[i]
52
+
53
+ bdg_h_deriv_2[0 : hamiltonian.no, 0 : hamiltonian.no] = hamiltonian.dHk(
54
+ k=k_point,
55
+ format="array",
56
+ )[j]
57
+ bdg_h_deriv_2[
58
+ hamiltonian.no : 2 * hamiltonian.no,
59
+ hamiltonian.no : 2 * hamiltonian.no,
60
+ ] = hamiltonian.dHk(k=-k_point, format="array")[j]
61
+
62
+ j_op_1 = _current_operator(bdg_h_deriv_1, wavefuncs)
63
+ j_op_2 = _current_operator(bdg_h_deriv_2, wavefuncs)
64
+
65
+ for m in range(len(wavefuncs)):
66
+ for n in range(len(wavefuncs)):
67
+ for p in range(len(wavefuncs)):
68
+ for q in range(len(wavefuncs)):
69
+ s_w = c_mnpq[m, n, p, q] * j_op_1[m, n] * j_op_2[q, p]
70
+ if m == n and p == q:
71
+ s_weight_conv[i, j] += s_w
72
+ else:
73
+ s_weight_geom[i, j] += s_w
74
+
75
+ return s_weight_conv, s_weight_geom
76
+
77
+
78
+ def _c_factor(e: npt.NDArray, psi: npt.NDArray, beta: float) -> npt.NDArray:
79
+ n = len(e)
80
+ c = np.zeros((n, n, n, n), dtype=np.complex128)
81
+ for i in range(n):
82
+ for j in range(n):
83
+ if np.isclose(e[i], e[j]):
84
+ f_term = -_fermi_dirac_derivative(e[i], beta)
85
+ else:
86
+ f_term = (_fermi_dirac(e[i], beta) - _fermi_dirac(e[j], beta)) / (e[i] - e[j])
87
+ for m in range(n):
88
+ for n_ in range(n):
89
+ for p in range(n):
90
+ for q in range(n):
91
+ c[m, n_, p, q] += f_term * (
92
+ psi[:, i].conj()[m]
93
+ * psi[:, j][n_]
94
+ * psi[:, j].conj()[p]
95
+ * psi[:, i][q]
96
+ )
97
+ return 2 * c
98
+
99
+
100
+ def _current_operator(h_deriv: npt.NDArray, psi: npt.NDArray) -> npt.NDArray:
101
+ return psi.conj().T @ h_deriv @ psi
102
+
103
+
104
+ def _fermi_dirac(energy: float, beta: float) -> float:
105
+ return 1.0 / (np.exp(beta * energy) + 1.0)
106
+
107
+
108
+ def _fermi_dirac_derivative(energy: float, beta: float) -> float:
109
+ f = _fermi_dirac(energy, beta)
110
+ return -beta * f * (1 - f)
quant_met/cli/__init__.py CHANGED
@@ -1,8 +1,3 @@
1
- # SPDX-FileCopyrightText: 2024 Tjark Sievers
2
- # SPDX-FileCopyrightText: 2025 Tjark Sievers
3
- #
4
- # SPDX-License-Identifier: MIT
5
-
6
1
  """
7
2
  Command-Line-Interface
8
3
  ======================
@@ -1,19 +1,15 @@
1
- # SPDX-FileCopyrightText: 2024 Tjark Sievers
2
- # SPDX-FileCopyrightText: 2025 Tjark Sievers
3
- #
4
- # SPDX-License-Identifier: MIT
5
-
6
1
  """Functions to run self-consistent calculation for the order parameter."""
7
2
 
8
3
  import logging
9
4
  from pathlib import Path
10
5
 
11
6
  import h5py
7
+ import numpy as np
8
+ import sisl
12
9
 
13
- from quant_met import mean_field
10
+ from quant_met import routines
14
11
  from quant_met.parameters import Parameters
15
-
16
- from ._utils import _hamiltonian_factory
12
+ from quant_met.parameters.control import CritTemp
17
13
 
18
14
  logger = logging.getLogger(__name__)
19
15
 
@@ -27,18 +23,26 @@ def crit_temp(parameters: Parameters) -> None:
27
23
  An instance of Parameters containing control settings, the model,
28
24
  and k-point specifications for the T_C calculation.
29
25
  """
26
+ if not isinstance(parameters.control, CritTemp):
27
+ err_msg = "Wrong parameters for crit-temp."
28
+ raise TypeError(err_msg)
29
+
30
30
  result_path = Path(parameters.control.outdir)
31
31
  result_path.mkdir(exist_ok=True, parents=True)
32
32
 
33
- h = _hamiltonian_factory(parameters=parameters.model, classname=parameters.model.name)
33
+ hamiltonian = sisl.get_sile(parameters.control.hamiltonian_file).read_hamiltonian()
34
+ k_grid_obj = sisl.MonkhorstPack(
35
+ hamiltonian.geometry,
36
+ [parameters.k_points.nk1, parameters.k_points.nk2, 1],
37
+ )
34
38
 
35
- delta_vs_temp, critical_temperatures, fit_fig = mean_field.search_crit_temp(
36
- h=h,
37
- k_space_grid=h.lattice.generate_bz_grid(
38
- ncols=parameters.k_points.nk1, nrows=parameters.k_points.nk2
39
- ),
39
+ delta_vs_temp, critical_temperatures, fit_fig = routines.search_crit_temp(
40
+ hamiltonian=hamiltonian,
41
+ kgrid=k_grid_obj,
42
+ hubbard_int_orbital_basis=np.array(parameters.control.hubbard_int_orbital_basis),
40
43
  epsilon=parameters.control.conv_treshold,
41
44
  max_iter=parameters.control.max_iter,
45
+ q=np.array(parameters.control.q),
42
46
  n_temp_points=parameters.control.n_temp_points,
43
47
  )
44
48
 
@@ -55,7 +59,5 @@ def crit_temp(parameters: Parameters) -> None:
55
59
  with h5py.File(result_file, mode="a") as file:
56
60
  for orbital, crit_temp_orbital in enumerate(critical_temperatures):
57
61
  file.attrs[f"T_C_{orbital}"] = crit_temp_orbital
58
- hamiltonian_file = result_path / f"{parameters.control.prefix}_sample_hamiltonian.hdf5"
59
- h.save(hamiltonian_file)
60
62
 
61
63
  logger.info("Results saved to %s", result_file)
quant_met/cli/main.py CHANGED
@@ -1,8 +1,3 @@
1
- # SPDX-FileCopyrightText: 2024 Tjark Sievers
2
- # SPDX-FileCopyrightText: 2025 Tjark Sievers
3
- #
4
- # SPDX-License-Identifier: MIT
5
-
6
1
  """Command line interface."""
7
2
 
8
3
  import logging
@@ -15,6 +10,8 @@ import yaml
15
10
  from quant_met.parameters import Parameters
16
11
 
17
12
  from .crit_temp import crit_temp
13
+ from .q_analysis import q_analysis
14
+ from .q_loop import q_loop
18
15
  from .scf import scf
19
16
 
20
17
  logger = logging.getLogger(__name__)
@@ -61,6 +58,12 @@ def cli(input_file: TextIO, *, debug: bool) -> None:
61
58
  case "crit-temp":
62
59
  logger.info("Starting T_C calculation.")
63
60
  crit_temp(params)
61
+ case "q-loop":
62
+ logger.info("Starting q-loop calculation.")
63
+ q_loop(params)
64
+ case "q-analysis":
65
+ logger.info("Starting analysis of q data.")
66
+ q_analysis(params)
64
67
  case _:
65
68
  logger.error("Calculation %s not found.", params.control.calculation)
66
69
  sys.exit(1)
@@ -0,0 +1,60 @@
1
+ """Functions to run self-consistent calculation for the order parameter."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import h5py
7
+ import pandas as pd
8
+ import sisl
9
+
10
+ from quant_met import routines
11
+ from quant_met.parameters import Parameters
12
+ from quant_met.parameters.control import QAnalysis
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ def q_analysis(parameters: Parameters) -> None:
18
+ """Self-consistent calculation for the order parameter.
19
+
20
+ Parameters
21
+ ----------
22
+ parameters: Parameters
23
+ An instance of Parameters containing control settings, the model,
24
+ and k-point specifications for the T_C calculation.
25
+ """
26
+ if not isinstance(parameters.control, QAnalysis):
27
+ err_msg = "Wrong parameters for q-loop."
28
+ raise TypeError(err_msg)
29
+
30
+ q_data: dict[str, pd.DataFrame] = {}
31
+ with h5py.File(f"{parameters.control.q_data}") as f:
32
+ for key in f:
33
+ q_data.update({key: pd.DataFrame()})
34
+
35
+ for key in q_data:
36
+ data: pd.DataFrame = pd.read_hdf(f"{parameters.control.q_data}", key=key)
37
+ q_data[key] = data
38
+
39
+ hamiltonian = sisl.get_sile(parameters.control.hamiltonian_file).read_hamiltonian()
40
+
41
+ (
42
+ lengths_vs_temp,
43
+ gap_and_current_fig,
44
+ ) = routines.get_lengths_vs_temp(q_data=q_data, hamiltonian=hamiltonian)
45
+
46
+ result_file = Path(f"{parameters.control.outdir}/{parameters.control.prefix}_sc_lengths.hdf5")
47
+ result_file.unlink()
48
+ lengths_vs_temp.to_hdf(result_file, key="lengths_vs_temp")
49
+ gap_and_current_fig.savefig(
50
+ f"{parameters.control.outdir}/{parameters.control.prefix}_gap_and_current_vs_q.pdf",
51
+ )
52
+
53
+ zero_temp_lengths, length_vs_temp_fig = routines.get_zero_temperature_values(
54
+ hamiltonian=hamiltonian,
55
+ lengths_vs_temp=lengths_vs_temp,
56
+ )
57
+ zero_temp_lengths.to_hdf(result_file, key="zero_temp_lengths")
58
+ length_vs_temp_fig.savefig(
59
+ f"{parameters.control.outdir}/{parameters.control.prefix}_lengths_vs_temperature.pdf",
60
+ )
@@ -0,0 +1,95 @@
1
+ """Functions to run self-consistent calculation for the order parameter."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import h5py
7
+ import numpy as np
8
+ import sisl
9
+
10
+ from quant_met import routines
11
+ from quant_met.parameters import Parameters
12
+ from quant_met.parameters.control import CritTemp, QLoop
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ def q_loop(parameters: Parameters) -> None:
18
+ """Self-consistent calculation for the order parameter.
19
+
20
+ Parameters
21
+ ----------
22
+ parameters: Parameters
23
+ An instance of Parameters containing control settings, the model,
24
+ and k-point specifications for the T_C calculation.
25
+ """
26
+ if not isinstance(parameters.control, QLoop):
27
+ err_msg = "Wrong parameters for q-loop."
28
+ raise TypeError(err_msg)
29
+
30
+ result_path = Path(parameters.control.outdir)
31
+ result_path.mkdir(exist_ok=True, parents=True)
32
+
33
+ hamiltonian = sisl.get_sile(parameters.control.hamiltonian_file).read_hamiltonian()
34
+ k_grid_obj = sisl.MonkhorstPack(
35
+ hamiltonian.geometry,
36
+ [parameters.k_points.nk1, parameters.k_points.nk2, 1],
37
+ )
38
+
39
+ if isinstance(parameters.control.crit_temp, CritTemp):
40
+ delta_vs_temp, critical_temperatures, fit_fig = routines.search_crit_temp(
41
+ hamiltonian=hamiltonian,
42
+ kgrid=k_grid_obj,
43
+ hubbard_int_orbital_basis=np.array(parameters.control.crit_temp.hubbard_int_orbital_basis),
44
+ epsilon=parameters.control.crit_temp.conv_treshold,
45
+ max_iter=parameters.control.crit_temp.max_iter,
46
+ n_temp_points=20,
47
+ )
48
+ logger.info("Search for T_C completed successfully.")
49
+ logger.info("Obtained T_Cs: %s", critical_temperatures)
50
+
51
+ fit_fig.savefig(
52
+ result_path / f"{parameters.control.crit_temp.prefix}_critical_temperatures_fit.pdf",
53
+ bbox_inches="tight",
54
+ )
55
+
56
+ result_file_crit_temp = (
57
+ result_path / f"{parameters.control.crit_temp.prefix}_critical_temperatures.hdf5"
58
+ )
59
+ if result_file_crit_temp.exists():
60
+ result_file_crit_temp.exists()
61
+ delta_vs_temp.to_hdf(result_file_crit_temp, key="delta_vs_temp")
62
+ with h5py.File(result_file_crit_temp, mode="a") as file:
63
+ for orbital, crit_temp_orbital in enumerate(critical_temperatures):
64
+ file.attrs[f"T_C_{orbital}"] = crit_temp_orbital
65
+
66
+ logger.info("Results saved to %s", result_file_crit_temp)
67
+ else:
68
+ critical_temperatures = []
69
+ with h5py.File(f"{parameters.control.crit_temp}", mode="r") as file:
70
+ for key, critical_temperature in file.attrs.items():
71
+ if key.startswith("T_C"):
72
+ critical_temperatures.append(critical_temperature)
73
+ logger.info("Read critical temperatures from file.")
74
+ logger.info("Obtained T_Cs: %s", critical_temperatures)
75
+
76
+ delta_vs_q = routines.loop_over_q(
77
+ hamiltonian=hamiltonian,
78
+ kgrid=k_grid_obj,
79
+ hubbard_int_orbital_basis=np.array(parameters.control.hubbard_int_orbital_basis),
80
+ epsilon=parameters.control.conv_treshold,
81
+ max_iter=parameters.control.max_iter,
82
+ n_q_points=parameters.control.n_q_points,
83
+ crit_temps=np.array(critical_temperatures),
84
+ )
85
+
86
+ result_file_q = result_path / f"{parameters.control.prefix}_q.hdf5"
87
+
88
+ if result_file_q.exists():
89
+ result_file_q.unlink()
90
+ for key, df in delta_vs_q.items():
91
+ df.to_hdf(result_file_q, key=f"temp_{float(key):.6f}")
92
+ with h5py.File(result_file_q, "a") as f:
93
+ grp = f[f"temp_{float(key):.6f}"]
94
+ grp.attrs["crit_temp"] = critical_temperatures
95
+ grp.attrs["temp"] = float(key)