quant-met 0.0.3__tar.gz → 0.0.4__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quant-met
3
- Version: 0.0.3
3
+ Version: 0.0.4
4
4
  Summary: Calculate superconductivity in flat-band systems.
5
5
  Author: Tjark Sievers
6
6
  Author-email: tsievers@physnet.uni-hamburg.de
@@ -8,7 +8,7 @@ requires-python = ">=3.11"
8
8
 
9
9
  [tool.poetry]
10
10
  name = "quant-met"
11
- version = "0.0.3"
11
+ version = "0.0.4"
12
12
  description = "Calculate superconductivity in flat-band systems."
13
13
  authors = ["Tjark Sievers <tsievers@physnet.uni-hamburg.de>"]
14
14
  readme = "README.md"
@@ -64,6 +64,8 @@ ignore = [
64
64
  "Q003",
65
65
  "S101", # This checks against using assert
66
66
  "PLR0913", # This checks against using more than 5 function arguments
67
+ "PLR2004", # Check against "magic values"
68
+ "T201", # Warn about print statements
67
69
  ]
68
70
 
69
71
 
@@ -44,12 +44,13 @@ from .free_energy import (
44
44
  free_energy_uniform_pairing,
45
45
  )
46
46
  from .graphene import GrapheneHamiltonian
47
- from .quantum_metric import quantum_metric
47
+ from .quantum_metric import quantum_metric, quantum_metric_bdg
48
48
  from .superfluid_weight import superfluid_weight
49
49
 
50
50
  __all__ = [
51
51
  "superfluid_weight",
52
52
  "quantum_metric",
53
+ "quantum_metric_bdg",
53
54
  "free_energy",
54
55
  "free_energy_complex_gap",
55
56
  "free_energy_real_gap",
@@ -54,29 +54,44 @@ class BaseHamiltonian(ABC):
54
54
  raise NotImplementedError
55
55
 
56
56
  @abstractmethod
57
- def _hamiltonian_one_point(self, k_point: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
57
+ def hamiltonian(self, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
58
+ """
59
+ Return the normal state Hamiltonian in orbital basis.
60
+
61
+ Parameters
62
+ ----------
63
+ k : :class:`numpy.ndarray`
64
+ List of k points.
65
+
66
+ Returns
67
+ -------
68
+ :class:`numpy.ndarray`
69
+ Hamiltonian in matrix form.
70
+
71
+ """
58
72
  raise NotImplementedError
59
73
 
60
74
  @abstractmethod
61
- def _hamiltonian_derivative_one_point(
62
- self, k_point: npt.NDArray[np.float64], directions: str
75
+ def hamiltonian_derivative(
76
+ self, k: npt.NDArray[np.float64], direction: str
63
77
  ) -> npt.NDArray[np.complex64]:
64
- raise NotImplementedError
78
+ """
79
+ Deriative of the Hamiltonian.
65
80
 
66
- def _bdg_hamiltonian_one_point(
67
- self, k_point: npt.NDArray[np.float64]
68
- ) -> npt.NDArray[np.complex64]:
69
- delta_matrix: npt.NDArray[np.complex64] = np.zeros(
70
- shape=(self.number_of_bands, self.number_of_bands), dtype=np.complex64
71
- )
72
- np.fill_diagonal(delta_matrix, self.delta_orbital_basis)
81
+ Parameters
82
+ ----------
83
+ k: :class:`numpy.ndarray`
84
+ List of k points.
85
+ direction: str
86
+ Direction for derivative, either 'x' oder 'y'.
73
87
 
74
- return np.block(
75
- [
76
- [self.hamiltonian(k_point), delta_matrix],
77
- [np.conjugate(delta_matrix), -np.conjugate(self.hamiltonian(-k_point))],
78
- ]
79
- )
88
+ Returns
89
+ -------
90
+ :class:`numpy.ndarray`
91
+ Derivative of Hamiltonian.
92
+
93
+ """
94
+ raise NotImplementedError
80
95
 
81
96
  def save(self, filename: pathlib.Path) -> None:
82
97
  """
@@ -88,7 +103,7 @@ class BaseHamiltonian(ABC):
88
103
  Filename to save the Hamiltonian to, should end in .hdf5
89
104
 
90
105
  """
91
- with h5py.File(f"{filename}", "a") as f:
106
+ with h5py.File(f"{filename}", "w") as f:
92
107
  f.create_dataset("delta", data=self.delta_orbital_basis)
93
108
  for key, value in vars(self).items():
94
109
  if not key.startswith("_"):
@@ -126,42 +141,32 @@ class BaseHamiltonian(ABC):
126
141
  BdG Hamiltonian.
127
142
 
128
143
  """
129
- if np.isnan(k).any() or np.isinf(k).any():
130
- msg = "k is NaN or Infinity"
131
- raise ValueError(msg)
144
+ assert _check_valid_array(k)
132
145
  if k.ndim == 1:
133
- h = self._bdg_hamiltonian_one_point(k)
134
- else:
135
- h = np.array([self._bdg_hamiltonian_one_point(k) for k in k])
136
- return h
146
+ k = np.expand_dims(k, axis=0)
137
147
 
138
- def hamiltonian(self, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
139
- """
140
- Return the normal state Hamiltonian in orbital basis.
148
+ h = np.zeros(
149
+ (k.shape[0], 2 * self.number_of_bands, 2 * self.number_of_bands), dtype=np.complex64
150
+ )
141
151
 
142
- Parameters
143
- ----------
144
- k : :class:`numpy.ndarray`
145
- List of k points.
152
+ h[:, 0 : self.number_of_bands, 0 : self.number_of_bands] = self.hamiltonian(k)
153
+ h[
154
+ :,
155
+ self.number_of_bands : 2 * self.number_of_bands,
156
+ self.number_of_bands : 2 * self.number_of_bands,
157
+ ] = -self.hamiltonian(-k).conjugate()
146
158
 
147
- Returns
148
- -------
149
- :class:`numpy.ndarray`
150
- Hamiltonian in matrix form.
159
+ for i in range(self.number_of_bands):
160
+ h[:, self.number_of_bands + i, i] = self.delta_orbital_basis[i]
161
+ h[:, 0:2, 2:4] = h[:, 2:4, 0:2].copy().conjugate()
151
162
 
152
- """
153
- assert _check_valid_array(k)
154
- if k.ndim == 1:
155
- h = self._hamiltonian_one_point(k)
156
- else:
157
- h = np.array([self._hamiltonian_one_point(k) for k in k])
158
- return h
163
+ return h.squeeze()
159
164
 
160
- def hamiltonian_derivative(
165
+ def bdg_hamiltonian_derivative(
161
166
  self, k: npt.NDArray[np.float64], direction: str
162
167
  ) -> npt.NDArray[np.complex64]:
163
168
  """
164
- Deriative of the Hamiltonian.
169
+ Deriative of the BdG Hamiltonian.
165
170
 
166
171
  Parameters
167
172
  ----------
@@ -178,10 +183,22 @@ class BaseHamiltonian(ABC):
178
183
  """
179
184
  assert _check_valid_array(k)
180
185
  if k.ndim == 1:
181
- h = self._hamiltonian_derivative_one_point(k, direction)
182
- else:
183
- h = np.array([self._hamiltonian_derivative_one_point(k, direction) for k in k])
184
- return h
186
+ k = np.expand_dims(k, axis=0)
187
+
188
+ h = np.zeros(
189
+ (k.shape[0], 2 * self.number_of_bands, 2 * self.number_of_bands), dtype=np.complex64
190
+ )
191
+
192
+ h[:, 0 : self.number_of_bands, 0 : self.number_of_bands] = self.hamiltonian_derivative(
193
+ k, direction
194
+ )
195
+ h[
196
+ :,
197
+ self.number_of_bands : 2 * self.number_of_bands,
198
+ self.number_of_bands : 2 * self.number_of_bands,
199
+ ] = -self.hamiltonian_derivative(-k, direction).conjugate()
200
+
201
+ return h.squeeze()
185
202
 
186
203
  def diagonalize_nonint(
187
204
  self, k: npt.NDArray[np.float64]
@@ -203,20 +220,20 @@ class BaseHamiltonian(ABC):
203
220
 
204
221
  """
205
222
  k_point_matrix = self.hamiltonian(k)
223
+ if k_point_matrix.ndim == 2:
224
+ k_point_matrix = np.expand_dims(k_point_matrix, axis=0)
225
+ k = np.expand_dims(k, axis=0)
206
226
 
207
- if k.ndim == 1:
208
- band_energies, bloch_wavefunctions = np.linalg.eigh(k_point_matrix)
209
- else:
210
- bloch_wavefunctions = np.zeros(
211
- (len(k), self.number_of_bands, self.number_of_bands),
212
- dtype=complex,
213
- )
214
- band_energies = np.zeros((len(k), self.number_of_bands))
227
+ bloch_wavefunctions = np.zeros(
228
+ (len(k), self.number_of_bands, self.number_of_bands),
229
+ dtype=complex,
230
+ )
231
+ band_energies = np.zeros((len(k), self.number_of_bands))
215
232
 
216
- for i in range(len(k)):
217
- band_energies[i], bloch_wavefunctions[i] = np.linalg.eigh(k_point_matrix[i])
233
+ for i in range(len(k)):
234
+ band_energies[i], bloch_wavefunctions[i] = np.linalg.eigh(k_point_matrix[i])
218
235
 
219
- return band_energies, bloch_wavefunctions
236
+ return band_energies.squeeze(), bloch_wavefunctions.squeeze()
220
237
 
221
238
  def diagonalize_bdg(
222
239
  self, k: npt.NDArray[np.float64]
@@ -238,20 +255,20 @@ class BaseHamiltonian(ABC):
238
255
 
239
256
  """
240
257
  bdg_matrix = self.bdg_hamiltonian(k)
258
+ if bdg_matrix.ndim == 2:
259
+ bdg_matrix = np.expand_dims(bdg_matrix, axis=0)
260
+ k = np.expand_dims(k, axis=0)
241
261
 
242
- if k.ndim == 1:
243
- bdg_energies, bdg_wavefunctions = np.linalg.eigh(bdg_matrix)
244
- else:
245
- bdg_wavefunctions = np.zeros(
246
- (len(k), 2 * self.number_of_bands, 2 * self.number_of_bands),
247
- dtype=np.complex64,
248
- )
249
- bdg_energies = np.zeros((len(k), 2 * self.number_of_bands))
262
+ bdg_wavefunctions = np.zeros(
263
+ (len(k), 2 * self.number_of_bands, 2 * self.number_of_bands),
264
+ dtype=np.complex64,
265
+ )
266
+ bdg_energies = np.zeros((len(k), 2 * self.number_of_bands))
250
267
 
251
- for i in range(len(k)):
252
- bdg_energies[i], bdg_wavefunctions[i] = np.linalg.eigh(bdg_matrix[i])
268
+ for i in range(len(k)):
269
+ bdg_energies[i], bdg_wavefunctions[i] = np.linalg.eigh(bdg_matrix[i])
253
270
 
254
- return bdg_energies, bdg_wavefunctions
271
+ return bdg_energies.squeeze(), bdg_wavefunctions.squeeze()
255
272
 
256
273
  def calculate_bandstructure(
257
274
  self,
@@ -274,23 +291,20 @@ class BaseHamiltonian(ABC):
274
291
  Band structure.
275
292
 
276
293
  """
277
- k_point_matrix = self.hamiltonian(k)
278
-
279
294
  results = pd.DataFrame(
280
295
  index=range(len(k)),
281
296
  dtype=float,
282
297
  )
298
+ energies, wavefunctions = self.diagonalize_nonint(k)
283
299
 
284
- for i in range(len(k)):
285
- energies, eigenvectors = np.linalg.eigh(k_point_matrix[i])
286
-
300
+ for i, (energy_k, wavefunction_k) in enumerate(zip(energies, wavefunctions, strict=False)):
287
301
  for band_index in range(self.number_of_bands):
288
- results.loc[i, f"band_{band_index}"] = energies[band_index]
302
+ results.loc[i, f"band_{band_index}"] = energy_k[band_index]
289
303
 
290
304
  if overlaps is not None:
291
305
  results.loc[i, f"wx_{band_index}"] = (
292
- np.abs(np.dot(eigenvectors[:, band_index], overlaps[0])) ** 2
293
- - np.abs(np.dot(eigenvectors[:, band_index], overlaps[1])) ** 2
306
+ np.abs(np.dot(wavefunction_k[:, band_index], overlaps[0])) ** 2
307
+ - np.abs(np.dot(wavefunction_k[:, band_index], overlaps[1])) ** 2
294
308
  )
295
309
 
296
310
  return results
@@ -4,10 +4,12 @@
4
4
 
5
5
  """Provides the implementation for the EG-X model."""
6
6
 
7
+ from typing import Any
8
+
7
9
  import numpy as np
8
10
  import numpy.typing as npt
9
11
 
10
- from ._utils import _validate_float
12
+ from ._utils import _check_valid_array, _validate_float
11
13
  from .base_hamiltonian import BaseHamiltonian
12
14
 
13
15
 
@@ -24,7 +26,11 @@ class EGXHamiltonian(BaseHamiltonian):
24
26
  coloumb_gr: float,
25
27
  coloumb_x: float,
26
28
  delta: npt.NDArray[np.complex64] | None = None,
29
+ *args: tuple[Any, ...],
30
+ **kwargs: tuple[dict[str, Any], ...],
27
31
  ) -> None:
32
+ del args
33
+ del kwargs
28
34
  self.hopping_gr = _validate_float(hopping_gr, "Hopping graphene")
29
35
  self.hopping_x = _validate_float(hopping_x, "Hopping impurity")
30
36
  self.hopping_x_gr_a = _validate_float(hopping_x_gr_a, "Hybridisation")
@@ -55,66 +61,113 @@ class EGXHamiltonian(BaseHamiltonian):
55
61
  def number_of_bands(self) -> int: # noqa: D102
56
62
  return self._number_of_bands
57
63
 
58
- def _hamiltonian_derivative_one_point(
64
+ def hamiltonian(self, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
65
+ """
66
+ Return the normal state Hamiltonian in orbital basis.
67
+
68
+ Parameters
69
+ ----------
70
+ k : :class:`numpy.ndarray`
71
+ List of k points.
72
+
73
+ Returns
74
+ -------
75
+ :class:`numpy.ndarray`
76
+ Hamiltonian in matrix form.
77
+
78
+ """
79
+ assert _check_valid_array(k)
80
+
81
+ t_gr = self.hopping_gr
82
+ t_x = self.hopping_x
83
+ a = self.lattice_constant
84
+ v = self.hopping_x_gr_a
85
+ mu = self.mu
86
+ if k.ndim == 1:
87
+ k = np.expand_dims(k, axis=0)
88
+
89
+ h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex64)
90
+
91
+ h[:, 0, 1] = -t_gr * (
92
+ np.exp(1j * k[:, 1] * a / np.sqrt(3))
93
+ + 2 * np.exp(-0.5j * a / np.sqrt(3) * k[:, 1]) * (np.cos(0.5 * a * k[:, 0]))
94
+ )
95
+
96
+ h[:, 1, 0] = h[:, 0, 1].conjugate()
97
+
98
+ h[:, 2, 0] = v
99
+ h[:, 0, 2] = v
100
+
101
+ h[:, 2, 2] = (
102
+ -2
103
+ * t_x
104
+ * (
105
+ np.cos(a * k[:, 0])
106
+ + 2 * np.cos(0.5 * a * k[:, 0]) * np.cos(0.5 * np.sqrt(3) * a * k[:, 1])
107
+ )
108
+ )
109
+ h[:, 0, 0] -= mu
110
+ h[:, 1, 1] -= mu
111
+ h[:, 2, 2] -= mu
112
+
113
+ return h.squeeze()
114
+
115
+ def hamiltonian_derivative(
59
116
  self, k: npt.NDArray[np.float64], direction: str
60
117
  ) -> npt.NDArray[np.complex64]:
118
+ """
119
+ Deriative of the Hamiltonian.
120
+
121
+ Parameters
122
+ ----------
123
+ k: :class:`numpy.ndarray`
124
+ List of k points.
125
+ direction: str
126
+ Direction for derivative, either 'x' oder 'y'.
127
+
128
+ Returns
129
+ -------
130
+ :class:`numpy.ndarray`
131
+ Derivative of Hamiltonian.
132
+
133
+ """
134
+ assert _check_valid_array(k)
61
135
  assert direction in ["x", "y"]
62
136
 
63
137
  t_gr = self.hopping_gr
64
138
  t_x = self.hopping_x
65
139
  a = self.lattice_constant
140
+ if k.ndim == 1:
141
+ k = np.expand_dims(k, axis=0)
66
142
 
67
- h = np.zeros((self.number_of_bands, self.number_of_bands), dtype=np.complex64)
143
+ h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex64)
68
144
 
69
145
  if direction == "x":
70
- h[0, 1] = t_gr * a * np.exp(-0.5j * a / np.sqrt(3) * k[1]) * np.sin(0.5 * a * k[0])
71
- h[1, 0] = h[0, 1].conjugate()
72
- h[2, 2] = (
146
+ h[:, 0, 1] = (
147
+ t_gr * a * np.exp(-0.5j * a / np.sqrt(3) * k[:, 1]) * np.sin(0.5 * a * k[:, 0])
148
+ )
149
+ h[:, 1, 0] = h[:, 0, 1].conjugate()
150
+ h[:, 2, 2] = (
73
151
  2
74
152
  * a
75
153
  * t_x
76
- * (np.sin(a * k[0]) + np.sin(0.5 * a * k[0]) * np.cos(0.5 * np.sqrt(3) * a * k[1]))
154
+ * (
155
+ np.sin(a * k[:, 0])
156
+ + np.sin(0.5 * a * k[:, 0]) * np.cos(0.5 * np.sqrt(3) * a * k[:, 1])
157
+ )
77
158
  )
78
159
  else:
79
- h[0, 1] = (
160
+ h[:, 0, 1] = (
80
161
  -t_gr
81
162
  * 1j
82
163
  * a
83
164
  / np.sqrt(3)
84
165
  * (
85
- np.exp(1j * a / np.sqrt(3) * k[1])
86
- - np.exp(-0.5j * a / np.sqrt(3) * k[1]) * np.cos(0.5 * a * k[0])
166
+ np.exp(1j * a / np.sqrt(3) * k[:, 1])
167
+ - np.exp(-0.5j * a / np.sqrt(3) * k[:, 1]) * np.cos(0.5 * a * k[:, 0])
87
168
  )
88
169
  )
89
- h[1, 0] = h[0, 1].conjugate()
90
- h[2, 2] = np.sqrt(3) * a * t_x * np.cos(0.5 * np.sqrt(3) * a * k[1])
91
-
92
- return h
93
-
94
- def _hamiltonian_one_point(self, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
95
- t_gr = self.hopping_gr
96
- t_x = self.hopping_x
97
- a = self.lattice_constant
98
- v = self.hopping_x_gr_a
99
- mu = self.mu
100
-
101
- h = np.zeros((self.number_of_bands, self.number_of_bands), dtype=np.complex64)
102
-
103
- h[0, 1] = -t_gr * (
104
- np.exp(1j * k[1] * a / np.sqrt(3))
105
- + 2 * np.exp(-0.5j * a / np.sqrt(3) * k[1]) * (np.cos(0.5 * a * k[0]))
106
- )
107
-
108
- h[1, 0] = h[0, 1].conjugate()
109
-
110
- h[2, 0] = v
111
- h[0, 2] = v
112
-
113
- h[2, 2] = (
114
- -2
115
- * t_x
116
- * (np.cos(a * k[0]) + 2 * np.cos(0.5 * a * k[0]) * np.cos(0.5 * np.sqrt(3) * a * k[1]))
117
- )
118
- h -= mu * np.eye(3, dtype=np.complex64)
170
+ h[:, 1, 0] = h[:, 0, 1].conjugate()
171
+ h[:, 2, 2] = np.sqrt(3) * a * t_x * np.cos(0.5 * np.sqrt(3) * a * k[:, 1])
119
172
 
120
- return h
173
+ return h.squeeze()
@@ -0,0 +1,142 @@
1
+ # SPDX-FileCopyrightText: 2024 Tjark Sievers
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ """Provides the implementation for Graphene."""
6
+
7
+ from typing import Any
8
+
9
+ import numpy as np
10
+ import numpy.typing as npt
11
+
12
+ from ._utils import _check_valid_array, _validate_float
13
+ from .base_hamiltonian import BaseHamiltonian
14
+
15
+
16
+ class GrapheneHamiltonian(BaseHamiltonian):
17
+ """Hamiltonian for Graphene."""
18
+
19
+ def __init__(
20
+ self,
21
+ t_nn: float,
22
+ a: float,
23
+ mu: float,
24
+ coulomb_gr: float,
25
+ delta: npt.NDArray[np.float64] | None = None,
26
+ *args: tuple[Any, ...],
27
+ **kwargs: tuple[dict[str, Any], ...],
28
+ ) -> None:
29
+ del args
30
+ del kwargs
31
+ self.t_nn = _validate_float(t_nn, "Hopping")
32
+ if a <= 0:
33
+ msg = "Lattice constant must be positive"
34
+ raise ValueError(msg)
35
+ self.a = _validate_float(a, "Lattice constant")
36
+ self.mu = _validate_float(mu, "Chemical potential")
37
+ self.coulomb_gr = _validate_float(coulomb_gr, "Coloumb interaction")
38
+ self._coloumb_orbital_basis = np.array([self.coulomb_gr, self.coulomb_gr])
39
+ self._number_of_bands = 2
40
+ if delta is None:
41
+ self._delta_orbital_basis = np.zeros(2)
42
+ else:
43
+ self._delta_orbital_basis = delta
44
+
45
+ @property
46
+ def number_of_bands(self) -> int: # noqa: D102
47
+ return self._number_of_bands
48
+
49
+ @property
50
+ def coloumb_orbital_basis(self) -> npt.NDArray[np.float64]: # noqa: D102
51
+ return self._coloumb_orbital_basis
52
+
53
+ @property
54
+ def delta_orbital_basis(self) -> npt.NDArray[np.float64]: # noqa: D102
55
+ return self._delta_orbital_basis
56
+
57
+ @delta_orbital_basis.setter
58
+ def delta_orbital_basis(self, new_delta: npt.NDArray[np.float64]) -> None:
59
+ self._delta_orbital_basis = new_delta
60
+
61
+ def hamiltonian(self, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
62
+ """
63
+ Return the normal state Hamiltonian in orbital basis.
64
+
65
+ Parameters
66
+ ----------
67
+ k : :class:`numpy.ndarray`
68
+ List of k points.
69
+
70
+ Returns
71
+ -------
72
+ :class:`numpy.ndarray`
73
+ Hamiltonian in matrix form.
74
+
75
+ """
76
+ assert _check_valid_array(k)
77
+ t_nn = self.t_nn
78
+ a = self.a
79
+ mu = self.mu
80
+ if k.ndim == 1:
81
+ k = np.expand_dims(k, axis=0)
82
+
83
+ h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex64)
84
+
85
+ h[:, 0, 1] = -t_nn * (
86
+ np.exp(1j * k[:, 1] * a / np.sqrt(3))
87
+ + 2 * np.exp(-0.5j * a / np.sqrt(3) * k[:, 1]) * (np.cos(0.5 * a * k[:, 0]))
88
+ )
89
+ h[:, 1, 0] = h[:, 0, 1].conjugate()
90
+ h[:, 0, 0] -= mu
91
+ h[:, 1, 1] -= mu
92
+
93
+ return h.squeeze()
94
+
95
+ def hamiltonian_derivative(
96
+ self, k: npt.NDArray[np.float64], direction: str
97
+ ) -> npt.NDArray[np.complex64]:
98
+ """
99
+ Deriative of the Hamiltonian.
100
+
101
+ Parameters
102
+ ----------
103
+ k: :class:`numpy.ndarray`
104
+ List of k points.
105
+ direction: str
106
+ Direction for derivative, either 'x' oder 'y'.
107
+
108
+ Returns
109
+ -------
110
+ :class:`numpy.ndarray`
111
+ Derivative of Hamiltonian.
112
+
113
+ """
114
+ assert _check_valid_array(k)
115
+ assert direction in ["x", "y"]
116
+
117
+ t_nn = self.t_nn
118
+ a = self.a
119
+ if k.ndim == 1:
120
+ k = np.expand_dims(k, axis=0)
121
+
122
+ h = np.zeros((k.shape[0], self.number_of_bands, self.number_of_bands), dtype=np.complex64)
123
+
124
+ if direction == "x":
125
+ h[:, 0, 1] = (
126
+ t_nn * a * np.exp(-0.5j * a / np.sqrt(3) * k[:, 1]) * np.sin(0.5 * a * k[:, 0])
127
+ )
128
+ h[:, 1, 0] = h[:, 0, 1].conjugate()
129
+ else:
130
+ h[:, 0, 1] = (
131
+ -t_nn
132
+ * 1j
133
+ * a
134
+ / np.sqrt(3)
135
+ * (
136
+ np.exp(1j * a / np.sqrt(3) * k[:, 1])
137
+ - np.exp(-0.5j * a / np.sqrt(3) * k[:, 1]) * np.cos(0.5 * a * k[:, 0])
138
+ )
139
+ )
140
+ h[:, 1, 0] = h[:, 0, 1].conjugate()
141
+
142
+ return h.squeeze()
@@ -0,0 +1,108 @@
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
+ bloch[k_index][:, band].conjugate()
48
+ @ h_derivative_direction_1[k_index]
49
+ @ bloch[k_index][:, n]
50
+ )
51
+ * (
52
+ bloch[k_index][:, n].conjugate()
53
+ @ h_derivative_direction_2[k_index]
54
+ @ bloch[k_index][:, band]
55
+ )
56
+ / (energies[k_index][band] - energies[k_index][n]) ** 2
57
+ )
58
+
59
+ return np.real(quantum_geom_tensor) / number_k_points
60
+
61
+
62
+ def quantum_metric_bdg(
63
+ h: BaseHamiltonian, k_grid: npt.NDArray[np.float64], band: int
64
+ ) -> npt.NDArray[np.float64]:
65
+ """Calculate the quantum metric in the BdG state.
66
+
67
+ Parameters
68
+ ----------
69
+ h : :class:`~quant_met.BaseHamiltonian`
70
+ Hamiltonian object.
71
+ k_grid : :class:`numpy.ndarray`
72
+ List of k points.
73
+ band : int
74
+ Index of band for which the quantum metric is calculated.
75
+
76
+ Returns
77
+ -------
78
+ :class:`numpy.ndarray`
79
+ Quantum metric in the normal state.
80
+
81
+ """
82
+ energies, bdg_functions = h.diagonalize_bdg(k_grid)
83
+
84
+ number_k_points = len(k_grid)
85
+
86
+ quantum_geom_tensor = np.zeros(shape=(2, 2), dtype=np.complex64)
87
+
88
+ for i, direction_1 in enumerate(["x", "y"]):
89
+ h_derivative_direction_1 = h.bdg_hamiltonian_derivative(k=k_grid, direction=direction_1)
90
+ for j, direction_2 in enumerate(["x", "y"]):
91
+ h_derivative_direction_2 = h.bdg_hamiltonian_derivative(k=k_grid, direction=direction_2)
92
+ for k_index in range(len(k_grid)):
93
+ for n in [i for i in range(h.number_of_bands) if i != band]:
94
+ quantum_geom_tensor[i, j] += (
95
+ (
96
+ bdg_functions[k_index][:, band].conjugate()
97
+ @ h_derivative_direction_1[k_index]
98
+ @ bdg_functions[k_index][:, n]
99
+ )
100
+ * (
101
+ bdg_functions[k_index][:, n].conjugate()
102
+ @ h_derivative_direction_2[k_index]
103
+ @ bdg_functions[k_index][:, band]
104
+ )
105
+ / (energies[k_index][band] - energies[k_index][n]) ** 2
106
+ )
107
+
108
+ return np.real(quantum_geom_tensor) / number_k_points
@@ -63,7 +63,7 @@ def _current_operator(
63
63
  for m in range(h.number_of_bands):
64
64
  for n in range(h.number_of_bands):
65
65
  j[m, n] = (
66
- np.conjugate(bloch[:, m])
66
+ bloch[:, m].conjugate()
67
67
  @ h.hamiltonian_derivative(direction=direction, k=k)
68
68
  @ bloch[:, n]
69
69
  )
@@ -89,7 +89,7 @@ def _w_matrix(
89
89
  for i in range(2 * h.number_of_bands):
90
90
  for m in range(h.number_of_bands):
91
91
  w_minus[i, m] = (
92
- np.tensordot(np.conjugate(bloch[:, m]), np.array([0, 1]), axes=0).reshape(-1)
92
+ np.tensordot(bloch[:, m].conjugate(), np.array([0, 1]), axes=0).reshape(-1)
93
93
  @ bdg_functions[:, i]
94
94
  )
95
95
 
@@ -124,9 +124,9 @@ def _c_factor(h: BaseHamiltonian, k: npt.NDArray[np.float64]) -> npt.NDArray[np.
124
124
  c_tmp -= _fermi_dirac_derivative()
125
125
 
126
126
  c_tmp *= (
127
- np.conjugate(w_minus[i, m])
127
+ w_minus[i, m].conjugate()
128
128
  * w_plus[j, n]
129
- * np.conjugate(w_minus[j, p])
129
+ * w_minus[j, p].conjugate()
130
130
  * w_minus[i, q]
131
131
  )
132
132
 
@@ -1,97 +0,0 @@
1
- # SPDX-FileCopyrightText: 2024 Tjark Sievers
2
- #
3
- # SPDX-License-Identifier: MIT
4
-
5
- """Provides the implementation for Graphene."""
6
-
7
- import numpy as np
8
- import numpy.typing as npt
9
-
10
- from ._utils import _validate_float
11
- from .base_hamiltonian import BaseHamiltonian
12
-
13
-
14
- class GrapheneHamiltonian(BaseHamiltonian):
15
- """Hamiltonian for Graphene."""
16
-
17
- def __init__(
18
- self,
19
- t_nn: float,
20
- a: float,
21
- mu: float,
22
- coulomb_gr: float,
23
- delta: npt.NDArray[np.float64] | None = None,
24
- ) -> None:
25
- self.t_nn = _validate_float(t_nn, "Hopping")
26
- if a <= 0:
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
34
- if delta is None:
35
- self._delta_orbital_basis = np.zeros(2)
36
- else:
37
- self._delta_orbital_basis = delta
38
-
39
- @property
40
- def number_of_bands(self) -> int: # noqa: D102
41
- return self._number_of_bands
42
-
43
- @property
44
- def coloumb_orbital_basis(self) -> npt.NDArray[np.float64]: # noqa: D102
45
- return self._coloumb_orbital_basis
46
-
47
- @property
48
- def delta_orbital_basis(self) -> npt.NDArray[np.float64]: # noqa: D102
49
- return self._delta_orbital_basis
50
-
51
- @delta_orbital_basis.setter
52
- def delta_orbital_basis(self, new_delta: npt.NDArray[np.float64]) -> None:
53
- self._delta_orbital_basis = new_delta
54
-
55
- def _hamiltonian_derivative_one_point(
56
- self, k: npt.NDArray[np.float64], direction: str
57
- ) -> npt.NDArray[np.complex64]:
58
- assert direction in ["x", "y"]
59
-
60
- t_nn = self.t_nn
61
- a = self.a
62
-
63
- h = np.zeros((self.number_of_bands, self.number_of_bands), dtype=np.complex64)
64
-
65
- if direction == "x":
66
- h[0, 1] = t_nn * a * np.exp(-0.5j * a / np.sqrt(3) * k[1]) * np.sin(0.5 * a * k[0])
67
- h[1, 0] = h[0, 1].conjugate()
68
- else:
69
- h[0, 1] = (
70
- -t_nn
71
- * 1j
72
- * a
73
- / np.sqrt(3)
74
- * (
75
- np.exp(1j * a / np.sqrt(3) * k[1])
76
- - np.exp(-0.5j * a / np.sqrt(3) * k[1]) * np.cos(0.5 * a * k[0])
77
- )
78
- )
79
- h[1, 0] = h[0, 1].conjugate()
80
-
81
- return h
82
-
83
- def _hamiltonian_one_point(self, k: npt.NDArray[np.float64]) -> npt.NDArray[np.complex64]:
84
- t_nn = self.t_nn
85
- a = self.a
86
- mu = self.mu
87
-
88
- h = np.zeros((self.number_of_bands, self.number_of_bands), dtype=np.complex64)
89
-
90
- h[0, 1] = -t_nn * (
91
- np.exp(1j * k[1] * a / np.sqrt(3))
92
- + 2 * np.exp(-0.5j * a / np.sqrt(3) * k[1]) * (np.cos(0.5 * a * k[0]))
93
- )
94
- h[1, 0] = h[0, 1].conjugate()
95
- h -= mu * np.eye(2)
96
-
97
- return h
@@ -1,59 +0,0 @@
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
File without changes
File without changes
File without changes