tbkit 0.6.2__tar.gz → 0.7.0__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.
Files changed (84) hide show
  1. {tbkit-0.6.2/tbkit.egg-info → tbkit-0.7.0}/PKG-INFO +2 -2
  2. {tbkit-0.6.2 → tbkit-0.7.0}/README.md +1 -1
  3. {tbkit-0.6.2 → tbkit-0.7.0}/pyproject.toml +1 -1
  4. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/__init__.py +1 -1
  5. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/bdg.py +112 -0
  6. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/error_handling.py +55 -6
  7. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/floquet.py +18 -1
  8. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/kspace.py +231 -46
  9. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/transport.py +187 -67
  10. {tbkit-0.6.2 → tbkit-0.7.0/tbkit.egg-info}/PKG-INFO +2 -2
  11. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_error_handling.py +12 -0
  12. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_error_handling_structures.py +4 -0
  13. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_floquet.py +14 -0
  14. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_interactions.py +58 -1
  15. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_kspace.py +10 -0
  16. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_smatrix.py +69 -1
  17. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_surface_spectral.py +18 -0
  18. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_topology.py +109 -0
  19. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_transport_response.py +45 -6
  20. {tbkit-0.6.2 → tbkit-0.7.0}/LICENSE +0 -0
  21. {tbkit-0.6.2 → tbkit-0.7.0}/setup.cfg +0 -0
  22. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/bridges.py +0 -0
  23. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/continuum.py +0 -0
  24. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/dos.py +0 -0
  25. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/exceptional.py +0 -0
  26. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/graphene.py +0 -0
  27. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/higher_order.py +0 -0
  28. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/io.py +0 -0
  29. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/kpm.py +0 -0
  30. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/lattice.py +0 -0
  31. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/lattices.py +0 -0
  32. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/meanfield.py +0 -0
  33. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/moire.py +0 -0
  34. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/neighbours.py +0 -0
  35. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/occupation.py +0 -0
  36. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/optics.py +0 -0
  37. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/orbital.py +0 -0
  38. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/plot.py +0 -0
  39. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/propagation.py +0 -0
  40. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/py.typed +0 -0
  41. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/save.py +0 -0
  42. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/slater_koster.py +0 -0
  43. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/system.py +0 -0
  44. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/topology.py +0 -0
  45. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/values.py +0 -0
  46. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit/wannier.py +0 -0
  47. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit.egg-info/SOURCES.txt +0 -0
  48. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit.egg-info/dependency_links.txt +0 -0
  49. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit.egg-info/requires.txt +0 -0
  50. {tbkit-0.6.2 → tbkit-0.7.0}/tbkit.egg-info/top_level.txt +0 -0
  51. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_analysis.py +0 -0
  52. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_berry_response.py +0 -0
  53. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_bridges.py +0 -0
  54. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_continuum.py +0 -0
  55. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_correlations.py +0 -0
  56. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_dos.py +0 -0
  57. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_exceptional.py +0 -0
  58. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_graphene.py +0 -0
  59. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_green_occupation.py +0 -0
  60. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_hall.py +0 -0
  61. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_higher_order.py +0 -0
  62. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_invariants.py +0 -0
  63. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_io.py +0 -0
  64. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_kpm.py +0 -0
  65. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_large_lattices.py +0 -0
  66. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_lattice.py +0 -0
  67. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_lattices.py +0 -0
  68. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_magnetic.py +0 -0
  69. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_moire.py +0 -0
  70. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_neighbours.py +0 -0
  71. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_non_hermitian_bands.py +0 -0
  72. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_optics.py +0 -0
  73. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_orbitals.py +0 -0
  74. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_periodic.py +0 -0
  75. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_plot.py +0 -0
  76. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_propagation.py +0 -0
  77. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_regressions.py +0 -0
  78. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_save.py +0 -0
  79. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_system.py +0 -0
  80. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_three_d.py +0 -0
  81. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_transport.py +0 -0
  82. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_values.py +0 -0
  83. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_wannier90.py +0 -0
  84. {tbkit-0.6.2 → tbkit-0.7.0}/tests/test_wannier_functions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tbkit
3
- Version: 0.6.2
3
+ Version: 0.7.0
4
4
  Summary: A Python package to build and solve Tight-Binding models.
5
5
  Author-email: Charles Poli <cpoli374@gmail.com>
6
6
  Maintainer-email: Charles Poli <cpoli374@gmail.com>
@@ -47,7 +47,7 @@ Dynamic: license-file
47
47
 
48
48
  | | |
49
49
  |:--|:-:|
50
- | Package | [![PyPI version](https://badgen.net/pypi/v/tbkit)](https://pypi.org/project/tbkit/) [![conda-forge](https://img.shields.io/conda/vn/conda-forge/tbkit)](https://anaconda.org/conda-forge/tbkit) [![Python versions](https://badgen.net/pypi/python/tbkit)](https://pypi.org/project/tbkit/) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23386289.svg)](https://doi.org/10.5281/zenodo.23386289) |
50
+ | Package | [![PyPI version](https://badgen.net/pypi/v/tbkit)](https://pypi.org/project/tbkit/) [![conda-forge](https://img.shields.io/conda/vn/conda-forge/tbkit)](https://anaconda.org/conda-forge/tbkit) [![Python versions](https://badgen.net/pypi/python/tbkit)](https://pypi.org/project/tbkit/) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23755191.svg)](https://doi.org/10.5281/zenodo.23755191) |
51
51
  | Quality | [![License](https://img.shields.io/github/license/cpoli/tbkit)](https://github.com/cpoli/tbkit/blob/master/LICENSE) [![CI](https://github.com/cpoli/tbkit/actions/workflows/ci.yml/badge.svg)](https://github.com/cpoli/tbkit/actions/workflows/ci.yml) [![Coverage](https://codecov.io/gh/cpoli/tbkit/branch/master/graph/badge.svg)](https://codecov.io/gh/cpoli/tbkit) |
52
52
  | Documentation | [![Docs](https://badgen.net/badge/docs/cpoli.github.io%2Ftbkit/blue)](https://cpoli.github.io/tbkit/) |
53
53
  | Downloads | [![Downloads](https://static.pepy.tech/badge/tbkit)](https://pepy.tech/project/tbkit) [![Downloads/Month](https://static.pepy.tech/badge/tbkit/month)](https://pepy.tech/project/tbkit) |
@@ -2,7 +2,7 @@
2
2
 
3
3
  | | |
4
4
  |:--|:-:|
5
- | Package | [![PyPI version](https://badgen.net/pypi/v/tbkit)](https://pypi.org/project/tbkit/) [![conda-forge](https://img.shields.io/conda/vn/conda-forge/tbkit)](https://anaconda.org/conda-forge/tbkit) [![Python versions](https://badgen.net/pypi/python/tbkit)](https://pypi.org/project/tbkit/) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23386289.svg)](https://doi.org/10.5281/zenodo.23386289) |
5
+ | Package | [![PyPI version](https://badgen.net/pypi/v/tbkit)](https://pypi.org/project/tbkit/) [![conda-forge](https://img.shields.io/conda/vn/conda-forge/tbkit)](https://anaconda.org/conda-forge/tbkit) [![Python versions](https://badgen.net/pypi/python/tbkit)](https://pypi.org/project/tbkit/) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23755191.svg)](https://doi.org/10.5281/zenodo.23755191) |
6
6
  | Quality | [![License](https://img.shields.io/github/license/cpoli/tbkit)](https://github.com/cpoli/tbkit/blob/master/LICENSE) [![CI](https://github.com/cpoli/tbkit/actions/workflows/ci.yml/badge.svg)](https://github.com/cpoli/tbkit/actions/workflows/ci.yml) [![Coverage](https://codecov.io/gh/cpoli/tbkit/branch/master/graph/badge.svg)](https://codecov.io/gh/cpoli/tbkit) |
7
7
  | Documentation | [![Docs](https://badgen.net/badge/docs/cpoli.github.io%2Ftbkit/blue)](https://cpoli.github.io/tbkit/) |
8
8
  | Downloads | [![Downloads](https://static.pepy.tech/badge/tbkit)](https://pepy.tech/project/tbkit) [![Downloads/Month](https://static.pepy.tech/badge/tbkit/month)](https://pepy.tech/project/tbkit) |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tbkit"
7
- version = "0.6.2"
7
+ version = "0.7.0"
8
8
  description = "A Python package to build and solve Tight-Binding models."
9
9
  readme = "README.md"
10
10
  license = "BSD-3-Clause"
@@ -6,7 +6,7 @@
6
6
 
7
7
  """tbkit: build and solve Tight-Binding models."""
8
8
 
9
- __version__ = "0.6.2"
9
+ __version__ = "0.7.0"
10
10
 
11
11
  __all__ = [
12
12
  "Lattice", "System", "Plot", "Propagation", "Save", "KSpace",
@@ -395,3 +395,115 @@ def s_wave_gap(
395
395
  else:
396
396
  error_handling.converged(False, 's_wave_gap')
397
397
  return GapResult(new, en, vec, it)
398
+
399
+
400
+ def superfluid_weight(
401
+ ks, delta: complex | NDArray, mu: float = 0., nk: int | tuple[int, ...] = 60,
402
+ temperature: float = 0., dq: float = 1e-3,
403
+ ) -> NDArray[np.float64]:
404
+ r'''
405
+ Get the superfluid weight of an s-wave superconductor,
406
+ :math:`D_{\mu\nu} = \partial^2\Omega/\partial A_\mu\partial A_\nu` at
407
+ :math:`\mathbf{A} = 0` (:math:`\hbar = e = 1`): the curvature of the
408
+ grand potential per unit volume in a uniform vector potential, which
409
+ gives the supercurrent :math:`j_\mu = -D_{\mu\nu}A_\nu` (London). *ks* is
410
+ the spin-up model; the spin-down electrons are its time-reversed
411
+ partners, :math:`h_\downarrow(\mathbf{k}) = h(-\mathbf{k})^*`, so the
412
+ Kramers pairs :math:`(\mathbf{k}\uparrow, -\mathbf{k}\downarrow)` pair
413
+ even when *ks* is a Chern band (for real hoppings, the spin-independent
414
+ model). In the Nambu basis
415
+ :math:`(c_{\mathbf{k}\uparrow}, c^\dagger_{-\mathbf{k}\downarrow})`,
416
+
417
+ .. math::
418
+
419
+ H_{\mathbf{A}}(\mathbf{k}) = \begin{pmatrix} h_{\mathbf{A}}(\mathbf{k})-\mu & \Delta \\
420
+ \Delta^* & -[h_{-\mathbf{A}}(\mathbf{k})-\mu]\end{pmatrix}\, ,\qquad
421
+ \Omega(\mathbf{A}) = \frac{1}{N_kV}\sum_{\mathbf{k}}\Big[\mathrm{Tr}\,
422
+ [h_{-\mathbf{A}}(\mathbf{k})-\mu] - T\sum_n\ln\big(1 + e^{-E_n/T}\big)\Big]\, ,
423
+
424
+ with :math:`h_{\mathbf{A}}` the Peierls Hamiltonian of
425
+ *get_ham_peierls* (phases on the bond vectors, orbital positions
426
+ included), :math:`\Delta = \mathrm{diag}(\Delta_i)` the onsite pairing,
427
+ :math:`E_n` the eigenvalues and :math:`V` the cell volume.
428
+ :math:`\Delta` is held fixed (not re-solved in the field), which is
429
+ exact when symmetry fixes it, e.g. uniform pairing. The derivatives are
430
+ central differences in :math:`\mathbf{A}`.
431
+
432
+ For a dispersive band it is the conventional :math:`n/m`. For an
433
+ isolated flat band at filling :math:`\nu`, with uniform :math:`\Delta`
434
+ small compared to the band gaps, there is no dispersion, and
435
+ :math:`D` is purely geometric (Peotta and Törmä, Nat. Commun. 6, 8944
436
+ (2015)),
437
+
438
+ .. math::
439
+
440
+ D_{\mu\nu} = 8\Delta\sqrt{\nu(1-\nu)}\int\frac{d^d\mathbf{k}}{(2\pi)^d}\,g_{\mu\nu}(\mathbf{k})
441
+ \, ,\qquad \mathrm{Tr}\,D \ge \frac{4\Delta}{\pi}\sqrt{\nu(1-\nu)}\,|C|\ \ (2D)\, ,
442
+
443
+ with :math:`g` the quantum metric of the band (see
444
+ *KSpace.quantum_geometric_tensor*) and :math:`C` its Chern number.
445
+
446
+ Parameters
447
+ ----------
448
+ ks : **KSpace** instance (Hermitian, orthogonal basis, spinless)
449
+ Spin-up model.
450
+ delta : Number, or array of norb numbers
451
+ Onsite pairing :math:`\Delta_i`.
452
+ mu : Real number, default 0
453
+ Chemical potential.
454
+ nk : Positive integer, or tuple of *dim* positive integers, default 60
455
+ k-mesh (see *mesh_grid*).
456
+ temperature : Positive real or zero, default 0
457
+ dq : Positive real, default 1e-3
458
+ Finite-difference step in :math:`\mathbf{A}`.
459
+
460
+ Returns
461
+ -------
462
+ D : Real ndarray, shape (dim, dim), in the k coordinates of *get_ham*
463
+
464
+ Examples
465
+ --------
466
+ Example usage::
467
+
468
+ # BCS chain: D = (1/2 pi) int dk 2t cos k (1 - xi/E)
469
+ chain = KSpace(lattices.chain())
470
+ chain.set_hopping([{'i': 0, 'j': 0, 'R': (1,), 't': -1.}])
471
+ d = superfluid_weight(chain, 0.2, mu=-0.5)
472
+ '''
473
+ from tbkit.kspace import KSpace
474
+ error_handling.kspace(ks, KSpace)
475
+ error_handling.hermitian_kspace(ks.is_hermitian(), ks._overlap_hop)
476
+ error_handling.spin_up_model(ks.spin)
477
+ error_handling.pairing_amplitudes(delta, ks.norb, 'delta')
478
+ error_handling.real_number(mu, 'mu')
479
+ error_handling.nk(nk, ks.dim)
480
+ error_handling.positive_real_zero(temperature, 'temperature')
481
+ error_handling.positive_real(dq, 'dq')
482
+ n, dim = ks.norb, ks.dim
483
+ k_cart = ks.mesh_grid(nk)[1] @ ks.k_basis.T
484
+ diag = np.arange(n)
485
+ pair = np.broadcast_to(np.asarray(delta, dtype='c16'), (n,))
486
+ volume = (2 * np.pi) ** dim / abs(np.linalg.det(ks.rec_vec_k))
487
+
488
+ def omega(q):
489
+ A = ks.k_basis @ q
490
+ hole = ks._bloch_ham(k_cart, A=-A) - mu * np.eye(n)
491
+ big = np.zeros((len(k_cart), 2 * n, 2 * n), 'c16')
492
+ big[:, :n, :n] = ks._bloch_ham(k_cart, A=A) - mu * np.eye(n)
493
+ big[:, n:, n:] = -hole
494
+ big[:, diag, diag + n] = pair
495
+ big[:, diag + n, diag] = pair.conj()
496
+ en = np.linalg.eigvalsh(big)
497
+ free = (-temperature * np.logaddexp(0., -en / temperature) if temperature > 0
498
+ else np.minimum(en, 0.))
499
+ return (np.trace(hole, axis1=1, axis2=2).real.sum() + free.sum()) / (len(k_cart) * volume)
500
+
501
+ step = dq * np.eye(dim)
502
+ w0 = omega(np.zeros(dim))
503
+ d = np.zeros((dim, dim))
504
+ for a in range(dim):
505
+ d[a, a] = (omega(step[a]) - 2 * w0 + omega(-step[a])) / dq ** 2
506
+ for b in range(a):
507
+ d[a, b] = d[b, a] = (omega(step[a] + step[b]) - omega(step[a] - step[b])
508
+ - omega(step[b] - step[a]) + omega(-step[a] - step[b])) / (4 * dq ** 2)
509
+ return d
@@ -1140,6 +1140,24 @@ def k_vector(vec, var_name, ndim):
1140
1140
  raise TypeError('\n\nParameter {} must contain real numbers.\n'.format(var_name))
1141
1141
 
1142
1142
 
1143
+ def k_points(k, var_name, ndim):
1144
+ '''
1145
+ Check that *k* is one k-point (see *k_vector*) or an array of shape
1146
+ (nk, *ndim*) of real numbers.
1147
+
1148
+ Raises
1149
+ ------
1150
+ ValueError
1151
+ Parameter *var_name* must be of shape (nk, ndim).
1152
+ '''
1153
+ if np.ndim(k) != 2:
1154
+ k_vector(k, var_name, ndim)
1155
+ return
1156
+ k = np.asarray(k)
1157
+ if k.shape[1] != ndim or not np.issubdtype(k.dtype, np.number) or np.iscomplexobj(k):
1158
+ raise ValueError('\n\nParameter {} must be a real array of shape (nk, {}).\n'.format(var_name, ndim))
1159
+
1160
+
1143
1161
  def ks(ks, ndim):
1144
1162
  '''
1145
1163
  Check the k-points passed to *kspace.get_bands*: a 2D array of shape
@@ -1568,6 +1586,23 @@ def is_symmetry(err, tol):
1568
1586
  '(deviation {:.3g}).\n'.format(err))
1569
1587
 
1570
1588
 
1589
+ def symmetry_algebra(u, v, tol):
1590
+ '''
1591
+ Check that two symmetry operators of the same kind agree up to a phase
1592
+ (in *kspace.KSpace.non_hermitian_class*, *v* is a product of others).
1593
+
1594
+ Raises
1595
+ ------
1596
+ ValueError
1597
+ The symmetry operators leave a unitary symmetry: block-diagonalize it first.
1598
+ '''
1599
+ phase = np.trace(u.conj().T @ v) / np.trace(u.conj().T @ u)
1600
+ if not np.allclose(v, phase * u, atol=tol):
1601
+ raise ValueError('\n\nThe symmetry operators leave a unitary symmetry (two products of '
1602
+ 'the same kind differ by more than a phase): block-diagonalize '
1603
+ 'the Hamiltonian first.\n')
1604
+
1605
+
1571
1606
  def square(sq, tol):
1572
1607
  '''
1573
1608
  Check that the square of an antiunitary operator is +-1.
@@ -3621,21 +3656,35 @@ def interaction(V, n):
3621
3656
  'numbers (one per site).\n'.format(n))
3622
3657
 
3623
3658
 
3624
- def pairing_amplitudes(delta, n):
3659
+ def pairing_amplitudes(delta, n, var_name='delta0'):
3625
3660
  '''
3626
- Check initial pairing amplitudes: a number, or n numbers.
3661
+ Check pairing amplitudes: a number, or n numbers.
3627
3662
 
3628
3663
  Raises
3629
3664
  ------
3630
3665
  ValueError
3631
- Parameter delta0 must be a number or n numbers.
3666
+ Parameter *var_name* must be a number or n numbers.
3632
3667
  '''
3633
3668
  if np.ndim(delta) == 0:
3634
- number(delta, 'delta0')
3669
+ number(delta, var_name)
3635
3670
  return
3636
3671
  if np.shape(delta) != (n,):
3637
- raise ValueError('\n\nParameter delta0 must be a number, or {} numbers '
3638
- '(one per site).\n'.format(n))
3672
+ raise ValueError('\n\nParameter {} must be a number, or {} numbers '
3673
+ '(one per site).\n'.format(var_name, n))
3674
+
3675
+
3676
+ def spin_up_model(spin):
3677
+ '''
3678
+ Check that a KSpace model is spinless (the spin-up electrons).
3679
+
3680
+ Raises
3681
+ ------
3682
+ ValueError
3683
+ This needs the spinless spin-up model.
3684
+ '''
3685
+ if spin:
3686
+ raise ValueError('\n\nThis needs a spinless model (spin=False): the spin-up '
3687
+ 'electrons, whose time-reversed partners are the spin-down ones.\n')
3639
3688
  # OPTICAL RESPONSE AND TRANSPORT (tbkit.optics, tbkit.transport)
3640
3689
  ####################################
3641
3690
 
@@ -681,7 +681,24 @@ class DrivenKSpace:
681
681
  H_F : Complex ndarray, shape (norb, norb)
682
682
  '''
683
683
  error_handling.k_vector(k, 'k', self.dim)
684
- return _heff(self.get_evolution(k), self.period, self.epsilon)
684
+ return self._hams(np.asarray(k, dtype='f8')[None])[0]
685
+
686
+ def _hams(self, ks: NDArray[np.float64]) -> NDArray[np.complex128]:
687
+ '''
688
+ Private method. *get_ham* at the k-points *ks* (shape (nk, dim)): the
689
+ evolutions of all the k-points advance together, one stacked
690
+ exponential per time step (the steps of *_grid_steps*), in chunks of
691
+ bounded memory.
692
+ '''
693
+ chunk = max(1, 400000 // (self.norb ** 2 * self.n_steps))
694
+ out = []
695
+ for c0 in range(0, len(ks), chunk):
696
+ hams, durations = self._grid_steps(ks[c0:c0 + chunk])
697
+ u = np.broadcast_to(np.eye(self.norb, dtype='c16'), (len(hams), self.norb, self.norb))
698
+ for s, dt in enumerate(durations):
699
+ u = LA.expm(-1j * dt * hams[:, s]) @ u
700
+ out += [_heff(uk, self.period, self.epsilon) for uk in u]
701
+ return np.array(out, dtype='c16').reshape(len(ks), self.norb, self.norb)
685
702
 
686
703
  def is_hermitian(self) -> bool:
687
704
  '''