FermiSimplex 0.1.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.
- fermisimplex-0.1.0/.gitignore +26 -0
- fermisimplex-0.1.0/CHANGELOG.md +14 -0
- fermisimplex-0.1.0/CITATION.cff +10 -0
- fermisimplex-0.1.0/CMakeLists.txt +31 -0
- fermisimplex-0.1.0/LICENSE +28 -0
- fermisimplex-0.1.0/PKG-INFO +217 -0
- fermisimplex-0.1.0/README.md +188 -0
- fermisimplex-0.1.0/ci/test_wheel.py +41 -0
- fermisimplex-0.1.0/cpp/CMakeLists.txt +457 -0
- fermisimplex-0.1.0/cpp/cmake/fermisimplex-config.cmake.in +9 -0
- fermisimplex-0.1.0/cpp/include/fermisimplex/certification.h +64 -0
- fermisimplex-0.1.0/cpp/include/fermisimplex/fermi_surface.h +42 -0
- fermisimplex-0.1.0/cpp/include/fermisimplex/fermisimplex.h +7 -0
- fermisimplex-0.1.0/cpp/include/fermisimplex/hamiltonian.h +49 -0
- fermisimplex-0.1.0/cpp/include/fermisimplex/integration.h +70 -0
- fermisimplex-0.1.0/cpp/include/fermisimplex/spectral_mesh.h +75 -0
- fermisimplex-0.1.0/cpp/src/certification/bounds/mu_bounds.cpp +108 -0
- fermisimplex-0.1.0/cpp/src/certification/bounds/mu_bounds.h +38 -0
- fermisimplex-0.1.0/cpp/src/certification/bounds/occupation_bounds.cpp +164 -0
- fermisimplex-0.1.0/cpp/src/certification/bounds/occupation_bounds.h +29 -0
- fermisimplex-0.1.0/cpp/src/certification/linalg/cholesky.cpp +43 -0
- fermisimplex-0.1.0/cpp/src/certification/linalg/cholesky.h +23 -0
- fermisimplex-0.1.0/cpp/src/certification/linalg/matrix.h +35 -0
- fermisimplex-0.1.0/cpp/src/certification/linalg/rotated_blocks.cpp +136 -0
- fermisimplex-0.1.0/cpp/src/certification/linalg/rotated_blocks.h +31 -0
- fermisimplex-0.1.0/cpp/src/certification/mesh_certificate.h +18 -0
- fermisimplex-0.1.0/cpp/src/certification/simplex/anchor_selection.cpp +78 -0
- fermisimplex-0.1.0/cpp/src/certification/simplex/anchor_selection.h +42 -0
- fermisimplex-0.1.0/cpp/src/certification/simplex/occupation_certificate.cpp +195 -0
- fermisimplex-0.1.0/cpp/src/certification/simplex/occupation_certificate.h +42 -0
- fermisimplex-0.1.0/cpp/src/certification/simplex/simplex_blocks.cpp +63 -0
- fermisimplex-0.1.0/cpp/src/certification/simplex/simplex_blocks.h +33 -0
- fermisimplex-0.1.0/cpp/src/certification/simplex/vertex_blocks.cpp +175 -0
- fermisimplex-0.1.0/cpp/src/certification/simplex/vertex_blocks.h +33 -0
- fermisimplex-0.1.0/cpp/src/certification/simplex_certificate.cpp +210 -0
- fermisimplex-0.1.0/cpp/src/core/simplex_geometry.h +47 -0
- fermisimplex-0.1.0/cpp/src/core/spectral_mesh.cpp +134 -0
- fermisimplex-0.1.0/cpp/src/core/tight_binding.cpp +211 -0
- fermisimplex-0.1.0/cpp/src/fermi_surface/adaptive_refinement.cpp +171 -0
- fermisimplex-0.1.0/cpp/src/fermi_surface/adaptive_refinement.h +17 -0
- fermisimplex-0.1.0/cpp/src/fermi_surface/fermi_surface.cpp +43 -0
- fermisimplex-0.1.0/cpp/src/fermi_surface/simplex_classification.cpp +63 -0
- fermisimplex-0.1.0/cpp/src/fermi_surface/simplex_classification.h +27 -0
- fermisimplex-0.1.0/cpp/src/fermi_surface/surface_extraction.cpp +266 -0
- fermisimplex-0.1.0/cpp/src/fermi_surface/surface_extraction.h +21 -0
- fermisimplex-0.1.0/cpp/src/fermi_surface/surface_triangulation.cpp +72 -0
- fermisimplex-0.1.0/cpp/src/fermi_surface/surface_triangulation.h +14 -0
- fermisimplex-0.1.0/cpp/src/integration/charge.cpp +298 -0
- fermisimplex-0.1.0/cpp/src/integration/charge.h +60 -0
- fermisimplex-0.1.0/cpp/src/integration/density.cpp +150 -0
- fermisimplex-0.1.0/cpp/src/integration/density.h +44 -0
- fermisimplex-0.1.0/cpp/src/integration/integration.cpp +330 -0
- fermisimplex-0.1.0/cpp/src/integration/projected_error.cpp +479 -0
- fermisimplex-0.1.0/cpp/src/integration/projected_error.h +40 -0
- fermisimplex-0.1.0/cpp/src/linalg/blas.cpp +216 -0
- fermisimplex-0.1.0/cpp/src/linalg/blas_lapack.h +74 -0
- fermisimplex-0.1.0/cpp/src/linalg/lapack.cpp +270 -0
- fermisimplex-0.1.0/pyproject.toml +100 -0
- fermisimplex-0.1.0/python/CMakeLists.txt +48 -0
- fermisimplex-0.1.0/python/fermisimplex/__init__.py +31 -0
- fermisimplex-0.1.0/python/fermisimplex/certification.py +45 -0
- fermisimplex-0.1.0/python/fermisimplex/hamiltonian.py +108 -0
- fermisimplex-0.1.0/python/fermisimplex/mesh.py +365 -0
- fermisimplex-0.1.0/python/src/bindings/arrays.h +52 -0
- fermisimplex-0.1.0/python/src/bindings/bindings.h +14 -0
- fermisimplex-0.1.0/python/src/bindings/certification.cpp +143 -0
- fermisimplex-0.1.0/python/src/bindings/fermi_surface.cpp +65 -0
- fermisimplex-0.1.0/python/src/bindings/integration_types.cpp +48 -0
- fermisimplex-0.1.0/python/src/bindings/module.cpp +14 -0
- fermisimplex-0.1.0/python/src/bindings/spectral_mesh.cpp +393 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
.pixi/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
.pytest_cache/
|
|
7
|
+
.ipynb_checkpoints/
|
|
8
|
+
.ruff_cache/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.coverage
|
|
11
|
+
htmlcov/
|
|
12
|
+
artifacts/
|
|
13
|
+
docs/generated/
|
|
14
|
+
|
|
15
|
+
build/
|
|
16
|
+
dist/
|
|
17
|
+
*.egg-info/
|
|
18
|
+
_skbuild/
|
|
19
|
+
CMakeCache.txt
|
|
20
|
+
CMakeFiles/
|
|
21
|
+
cmake-build-*/
|
|
22
|
+
compile_commands.json
|
|
23
|
+
|
|
24
|
+
*.so
|
|
25
|
+
*.dylib
|
|
26
|
+
*.dll
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to FermiSimplex are documented in this file.
|
|
4
|
+
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
## 0.1.0 - 2026-07-28
|
|
8
|
+
|
|
9
|
+
- Added adaptive Fermi-surface extraction, charge integration, and density
|
|
10
|
+
matrices through a shared Python and C++ numerical core.
|
|
11
|
+
- Added occupation certification, projected charge-error estimation, and
|
|
12
|
+
reusable eigensystem caching on adaptive simplex meshes.
|
|
13
|
+
- Added production tests, performance benchmarks, examples, and visual
|
|
14
|
+
documentation.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use FermiSimplex, please cite it using this metadata."
|
|
3
|
+
title: "FermiSimplex"
|
|
4
|
+
version: "0.1.0"
|
|
5
|
+
date-released: "2026-07-28"
|
|
6
|
+
authors:
|
|
7
|
+
- family-names: "Vilkelis"
|
|
8
|
+
given-names: "Kostas"
|
|
9
|
+
license: "BSD-3-Clause"
|
|
10
|
+
repository-code: "https://gitlab.kwant-project.org/qt/lineartetrahedron"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.28...3.30)
|
|
2
|
+
|
|
3
|
+
project(
|
|
4
|
+
FermiSimplex
|
|
5
|
+
VERSION 0.1.0
|
|
6
|
+
LANGUAGES CXX
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
|
10
|
+
set(FERMISIMPLEX_TOP_LEVEL_DEFAULT ON)
|
|
11
|
+
include(CTest)
|
|
12
|
+
else()
|
|
13
|
+
set(FERMISIMPLEX_TOP_LEVEL_DEFAULT OFF)
|
|
14
|
+
endif()
|
|
15
|
+
|
|
16
|
+
option(
|
|
17
|
+
FERMISIMPLEX_BUILD_PYTHON
|
|
18
|
+
"Build the FermiSimplex Python extension"
|
|
19
|
+
"${FERMISIMPLEX_TOP_LEVEL_DEFAULT}"
|
|
20
|
+
)
|
|
21
|
+
option(
|
|
22
|
+
FERMISIMPLEX_BUILD_TESTING
|
|
23
|
+
"Build the FermiSimplex C++ tests"
|
|
24
|
+
"${FERMISIMPLEX_TOP_LEVEL_DEFAULT}"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
add_subdirectory(cpp)
|
|
28
|
+
|
|
29
|
+
if(FERMISIMPLEX_BUILD_PYTHON)
|
|
30
|
+
add_subdirectory(python)
|
|
31
|
+
endif()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Kostas Vilkelis
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
16
|
+
may be used to endorse or promote products derived from this software without
|
|
17
|
+
specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
20
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
21
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
23
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
24
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
25
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
26
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
27
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
28
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: FermiSimplex
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Adaptive spectral calculations with simplex occupation certification
|
|
5
|
+
Keywords: adaptive mesh,electronic structure,Fermi surface,scientific computing
|
|
6
|
+
Author: Kostas Vilkelis
|
|
7
|
+
License-Expression: BSD-3-Clause
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Operating System :: MacOS
|
|
12
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: C++
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
20
|
+
Project-URL: Repository, https://gitlab.kwant-project.org/qt/lineartetrahedron
|
|
21
|
+
Project-URL: Mirror, https://github.com/Kostusas/FermiSimplex
|
|
22
|
+
Project-URL: Documentation, https://github.com/Kostusas/FermiSimplex/blob/main/docs/showcase.md
|
|
23
|
+
Project-URL: Changelog, https://github.com/Kostusas/FermiSimplex/blob/main/CHANGELOG.md
|
|
24
|
+
Requires-Python: <3.14,>=3.11
|
|
25
|
+
Requires-Dist: numpy>=2.0
|
|
26
|
+
Provides-Extra: examples
|
|
27
|
+
Requires-Dist: matplotlib>=3.8; extra == "examples"
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# FermiSimplex
|
|
31
|
+
|
|
32
|
+
**Adaptive, occupation-certified spectral calculations on simplex meshes.**
|
|
33
|
+
|
|
34
|
+
FermiSimplex finds Fermi surfaces and computes zero-temperature charge and
|
|
35
|
+
density matrices without paying for a dense momentum grid. Its central object
|
|
36
|
+
is the local occupation
|
|
37
|
+
|
|
38
|
+
$$
|
|
39
|
+
N(k; \mu) = \mathrm{Tr}\left[\Theta\left(\mu I - H(k)\right)\right],
|
|
40
|
+
$$
|
|
41
|
+
|
|
42
|
+
and its central question is simple: *can the occupation be proved constant on
|
|
43
|
+
this simplex, or should we look more closely?*
|
|
44
|
+
|
|
45
|
+
The upstream development repository is
|
|
46
|
+
[GitLab](https://gitlab.kwant-project.org/qt/lineartetrahedron); the
|
|
47
|
+
[GitHub repository](https://github.com/Kostusas/FermiSimplex) is a public
|
|
48
|
+
mirror.
|
|
49
|
+
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
See the [visual Python tour][visual-tour] for a presentation-ready
|
|
53
|
+
introduction with real adaptive sampling traces, multiband examples, and a
|
|
54
|
+
rotating noble-metal-inspired three-dimensional surface.
|
|
55
|
+
|
|
56
|
+
- 🛡️ **Gapped-region proofs** combine cached eigensystems with rigorous spectral
|
|
57
|
+
bounds to exclude a Fermi-level crossing throughout a simplex and to bound
|
|
58
|
+
the remaining charge.
|
|
59
|
+
- ⚡ **Adaptive sampling**, built on
|
|
60
|
+
[AdaptiveSimplex](https://gitlab.kwant-project.org/qt/adaptivesimplex),
|
|
61
|
+
concentrates diagonalizations near unresolved Fermi surfaces instead of
|
|
62
|
+
refining the entire Brillouin zone uniformly.
|
|
63
|
+
- 🚀 **Numerical efficiency by design:** adaptive refinement, shared spectral
|
|
64
|
+
caching, and the compiled numerical core avoid repeated work as the Fermi
|
|
65
|
+
surface becomes progressively sharper.
|
|
66
|
+
- 🎯 **Projected charge estimates** compare sampled projected eigenvalues with
|
|
67
|
+
vertex-linear interpolation only in the bands whose occupation is still
|
|
68
|
+
ambiguous.
|
|
69
|
+
- 🧩 **Python and C++** share one numerical core; models can be dense callables
|
|
70
|
+
or translation-invariant tight-binding Hamiltonians.
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
From a source checkout with a C++20 compiler and BLAS/LAPACK available:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pip install .
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The model below produces the three-dimensional surface shown above:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
import numpy as np
|
|
84
|
+
|
|
85
|
+
from fermisimplex import SpectralMesh
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def hamiltonian(kx, ky, kz):
|
|
89
|
+
phase = 2 * np.pi * np.array([kx, ky, kz])
|
|
90
|
+
return np.array([[np.cos(phase).sum()]], dtype=complex)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
mesh = SpectralMesh(hamiltonian)
|
|
94
|
+
surface = mesh.fermi_surface(
|
|
95
|
+
mu=0.17,
|
|
96
|
+
min_feature_size=0.07,
|
|
97
|
+
curvature_bound=(2 * np.pi) ** 2,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
surface.points # (npoints, 3)
|
|
101
|
+
surface.cells # (ntriangles, 3)
|
|
102
|
+
surface.cell_bands # band index for every triangle
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The coordinates are reduced coordinates in $[0,1]^d$. Here
|
|
106
|
+
$M=(2\pi)^2$ bounds every directional second derivative of the scalar
|
|
107
|
+
Hamiltonian. `SpectralMesh` infers the momentum-space dimension from the
|
|
108
|
+
callable arguments and the matrix dimension by evaluating it at the origin.
|
|
109
|
+
Callables receive separate coordinates: `hamiltonian(kx, ky, ...)`.
|
|
110
|
+
|
|
111
|
+

|
|
112
|
+
|
|
113
|
+
The same `SpectralMesh` can drive the other observables and reuse every
|
|
114
|
+
eigensystem it has already computed:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
charge = mesh.integrate_charge(
|
|
118
|
+
mu=0.17,
|
|
119
|
+
target_error=1e-2,
|
|
120
|
+
max_refinements=10_000,
|
|
121
|
+
curvature_bound=(2 * np.pi) ** 2,
|
|
122
|
+
)
|
|
123
|
+
density = mesh.integrate_density_matrix(
|
|
124
|
+
mu=0.17,
|
|
125
|
+
lattice_vectors=[(0, 0, 0), (1, 0, 0)],
|
|
126
|
+
target_error=1e-2,
|
|
127
|
+
max_refinements=10_000,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
charge.value
|
|
131
|
+
charge.stopping_error
|
|
132
|
+
charge.certified_error_bound
|
|
133
|
+
density.matrices # (number of lattice vectors, ndof, ndof)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
For a tight-binding model,
|
|
137
|
+
|
|
138
|
+
$$
|
|
139
|
+
H(k)=\sum_R H_R e^{-2\pi i k\cdot R},
|
|
140
|
+
$$
|
|
141
|
+
|
|
142
|
+
pass `{R: H_R, ...}` directly to `SpectralMesh`. Opposite hoppings are checked
|
|
143
|
+
for $H_{-R}=H_R^\dagger$.
|
|
144
|
+
|
|
145
|
+
## What does the certificate prove?
|
|
146
|
+
|
|
147
|
+
At each simplex, FermiSimplex asks: **can the occupation change between the
|
|
148
|
+
sampled vertices?** It combines their eigensystems with `curvature_bound`,
|
|
149
|
+
which limits how much the Hamiltonian can bend in between. If occupied and
|
|
150
|
+
unoccupied trial subspaces remain on opposite sides of $\mu$, the occupation
|
|
151
|
+
is fixed everywhere—without sampling the interior.
|
|
152
|
+
|
|
153
|
+
- **Certified:** no Fermi surface crosses the simplex.
|
|
154
|
+
- **Partially certified:** rigorous lower and upper occupation bounds remain.
|
|
155
|
+
- **Inconclusive:** this is not a gapless verdict; FermiSimplex refines and
|
|
156
|
+
tries again.
|
|
157
|
+
|
|
158
|
+
Every charge and Fermi-surface simplex is checked. The remaining uncertainty
|
|
159
|
+
becomes `charge.certified_error_bound`; `surface.coverage_certified` concerns
|
|
160
|
+
classification down to `min_feature_size`, not topology or geometric accuracy.
|
|
161
|
+
Density matrices currently use adaptive estimates instead.
|
|
162
|
+
|
|
163
|
+
The guarantee assumes a valid `curvature_bound`. Omitting it, `None`, and
|
|
164
|
+
`0.0` all assert zero curvature; none disables certification. See the
|
|
165
|
+
[mathematics guide][mathematics] for the proof and error bounds.
|
|
166
|
+
|
|
167
|
+
## API at a glance
|
|
168
|
+
|
|
169
|
+
- `SpectralMesh`: accept a callable or tight-binding dictionary and own the
|
|
170
|
+
adaptive geometry and cached eigensystems.
|
|
171
|
+
- `certify_simplex`: certify supplied vertex eigenpairs directly; eigenvalues
|
|
172
|
+
must be finite and ascending, and eigenvector columns must be finite and
|
|
173
|
+
orthonormal. These performance-sensitive numerical preconditions are not
|
|
174
|
+
rechecked.
|
|
175
|
+
- `mesh.integrate_charge`: adaptive filling and $dQ/d\mu$.
|
|
176
|
+
- `mesh.integrate_density_matrix`: real-space density-matrix components.
|
|
177
|
+
- `mesh.fermi_surface`: band-labelled points and cells in reduced coordinates.
|
|
178
|
+
|
|
179
|
+
Adaptive controls such as `target_error`, `max_refinements`, and
|
|
180
|
+
`preview_depth` are ordinary keyword arguments on the calculation that uses
|
|
181
|
+
them—there is no separate options object. Charge calculations default to
|
|
182
|
+
`preview_depth=0` because their sampled projected-error estimate drives
|
|
183
|
+
refinement intrinsically; positive depths are intended for explicit
|
|
184
|
+
diagnostic comparisons.
|
|
185
|
+
|
|
186
|
+
See the [visual Python tour][visual-tour], runnable
|
|
187
|
+
[quick start][quick-start], and
|
|
188
|
+
[two-band plotting example][fermi-example], the
|
|
189
|
+
[visual-generation notes][visuals], and the
|
|
190
|
+
[build and architecture guide][development].
|
|
191
|
+
|
|
192
|
+
## Development
|
|
193
|
+
|
|
194
|
+
AdaptiveSimplex provides the mesh geometry, refinement, vertex caching, and
|
|
195
|
+
cut-simplex integration; FermiSimplex adds the spectral models, certificates,
|
|
196
|
+
and observable-specific algorithms.
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
pixi run test
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
This builds the standalone C++ library, verifies an installed downstream CMake
|
|
203
|
+
consumer, rebuilds the Python extension, and runs the Python tests. The dense
|
|
204
|
+
60-band stress case lives in [benchmarks/fermi_surface_60.py][stress-benchmark].
|
|
205
|
+
|
|
206
|
+
FermiSimplex is licensed under the BSD 3-Clause license. If you use it in
|
|
207
|
+
research, please cite the metadata in [CITATION.cff][citation].
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
[visual-tour]: https://github.com/Kostusas/FermiSimplex/blob/main/docs/showcase.md
|
|
211
|
+
[mathematics]: https://github.com/Kostusas/FermiSimplex/blob/main/docs/mathematics.md
|
|
212
|
+
[quick-start]: https://github.com/Kostusas/FermiSimplex/blob/main/examples/quick_start.py
|
|
213
|
+
[fermi-example]: https://github.com/Kostusas/FermiSimplex/blob/main/examples/fermi_surface.py
|
|
214
|
+
[visuals]: https://github.com/Kostusas/FermiSimplex/blob/main/docs/visuals.md
|
|
215
|
+
[development]: https://github.com/Kostusas/FermiSimplex/blob/main/docs/development.md
|
|
216
|
+
[stress-benchmark]: https://github.com/Kostusas/FermiSimplex/blob/main/benchmarks/fermi_surface_60.py
|
|
217
|
+
[citation]: https://github.com/Kostusas/FermiSimplex/blob/main/CITATION.cff
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# FermiSimplex
|
|
2
|
+
|
|
3
|
+
**Adaptive, occupation-certified spectral calculations on simplex meshes.**
|
|
4
|
+
|
|
5
|
+
FermiSimplex finds Fermi surfaces and computes zero-temperature charge and
|
|
6
|
+
density matrices without paying for a dense momentum grid. Its central object
|
|
7
|
+
is the local occupation
|
|
8
|
+
|
|
9
|
+
$$
|
|
10
|
+
N(k; \mu) = \mathrm{Tr}\left[\Theta\left(\mu I - H(k)\right)\right],
|
|
11
|
+
$$
|
|
12
|
+
|
|
13
|
+
and its central question is simple: *can the occupation be proved constant on
|
|
14
|
+
this simplex, or should we look more closely?*
|
|
15
|
+
|
|
16
|
+
The upstream development repository is
|
|
17
|
+
[GitLab](https://gitlab.kwant-project.org/qt/lineartetrahedron); the
|
|
18
|
+
[GitHub repository](https://github.com/Kostusas/FermiSimplex) is a public
|
|
19
|
+
mirror.
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
See the [visual Python tour][visual-tour] for a presentation-ready
|
|
24
|
+
introduction with real adaptive sampling traces, multiband examples, and a
|
|
25
|
+
rotating noble-metal-inspired three-dimensional surface.
|
|
26
|
+
|
|
27
|
+
- 🛡️ **Gapped-region proofs** combine cached eigensystems with rigorous spectral
|
|
28
|
+
bounds to exclude a Fermi-level crossing throughout a simplex and to bound
|
|
29
|
+
the remaining charge.
|
|
30
|
+
- ⚡ **Adaptive sampling**, built on
|
|
31
|
+
[AdaptiveSimplex](https://gitlab.kwant-project.org/qt/adaptivesimplex),
|
|
32
|
+
concentrates diagonalizations near unresolved Fermi surfaces instead of
|
|
33
|
+
refining the entire Brillouin zone uniformly.
|
|
34
|
+
- 🚀 **Numerical efficiency by design:** adaptive refinement, shared spectral
|
|
35
|
+
caching, and the compiled numerical core avoid repeated work as the Fermi
|
|
36
|
+
surface becomes progressively sharper.
|
|
37
|
+
- 🎯 **Projected charge estimates** compare sampled projected eigenvalues with
|
|
38
|
+
vertex-linear interpolation only in the bands whose occupation is still
|
|
39
|
+
ambiguous.
|
|
40
|
+
- 🧩 **Python and C++** share one numerical core; models can be dense callables
|
|
41
|
+
or translation-invariant tight-binding Hamiltonians.
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
From a source checkout with a C++20 compiler and BLAS/LAPACK available:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install .
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The model below produces the three-dimensional surface shown above:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import numpy as np
|
|
55
|
+
|
|
56
|
+
from fermisimplex import SpectralMesh
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def hamiltonian(kx, ky, kz):
|
|
60
|
+
phase = 2 * np.pi * np.array([kx, ky, kz])
|
|
61
|
+
return np.array([[np.cos(phase).sum()]], dtype=complex)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
mesh = SpectralMesh(hamiltonian)
|
|
65
|
+
surface = mesh.fermi_surface(
|
|
66
|
+
mu=0.17,
|
|
67
|
+
min_feature_size=0.07,
|
|
68
|
+
curvature_bound=(2 * np.pi) ** 2,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
surface.points # (npoints, 3)
|
|
72
|
+
surface.cells # (ntriangles, 3)
|
|
73
|
+
surface.cell_bands # band index for every triangle
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The coordinates are reduced coordinates in $[0,1]^d$. Here
|
|
77
|
+
$M=(2\pi)^2$ bounds every directional second derivative of the scalar
|
|
78
|
+
Hamiltonian. `SpectralMesh` infers the momentum-space dimension from the
|
|
79
|
+
callable arguments and the matrix dimension by evaluating it at the origin.
|
|
80
|
+
Callables receive separate coordinates: `hamiltonian(kx, ky, ...)`.
|
|
81
|
+
|
|
82
|
+

|
|
83
|
+
|
|
84
|
+
The same `SpectralMesh` can drive the other observables and reuse every
|
|
85
|
+
eigensystem it has already computed:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
charge = mesh.integrate_charge(
|
|
89
|
+
mu=0.17,
|
|
90
|
+
target_error=1e-2,
|
|
91
|
+
max_refinements=10_000,
|
|
92
|
+
curvature_bound=(2 * np.pi) ** 2,
|
|
93
|
+
)
|
|
94
|
+
density = mesh.integrate_density_matrix(
|
|
95
|
+
mu=0.17,
|
|
96
|
+
lattice_vectors=[(0, 0, 0), (1, 0, 0)],
|
|
97
|
+
target_error=1e-2,
|
|
98
|
+
max_refinements=10_000,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
charge.value
|
|
102
|
+
charge.stopping_error
|
|
103
|
+
charge.certified_error_bound
|
|
104
|
+
density.matrices # (number of lattice vectors, ndof, ndof)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
For a tight-binding model,
|
|
108
|
+
|
|
109
|
+
$$
|
|
110
|
+
H(k)=\sum_R H_R e^{-2\pi i k\cdot R},
|
|
111
|
+
$$
|
|
112
|
+
|
|
113
|
+
pass `{R: H_R, ...}` directly to `SpectralMesh`. Opposite hoppings are checked
|
|
114
|
+
for $H_{-R}=H_R^\dagger$.
|
|
115
|
+
|
|
116
|
+
## What does the certificate prove?
|
|
117
|
+
|
|
118
|
+
At each simplex, FermiSimplex asks: **can the occupation change between the
|
|
119
|
+
sampled vertices?** It combines their eigensystems with `curvature_bound`,
|
|
120
|
+
which limits how much the Hamiltonian can bend in between. If occupied and
|
|
121
|
+
unoccupied trial subspaces remain on opposite sides of $\mu$, the occupation
|
|
122
|
+
is fixed everywhere—without sampling the interior.
|
|
123
|
+
|
|
124
|
+
- **Certified:** no Fermi surface crosses the simplex.
|
|
125
|
+
- **Partially certified:** rigorous lower and upper occupation bounds remain.
|
|
126
|
+
- **Inconclusive:** this is not a gapless verdict; FermiSimplex refines and
|
|
127
|
+
tries again.
|
|
128
|
+
|
|
129
|
+
Every charge and Fermi-surface simplex is checked. The remaining uncertainty
|
|
130
|
+
becomes `charge.certified_error_bound`; `surface.coverage_certified` concerns
|
|
131
|
+
classification down to `min_feature_size`, not topology or geometric accuracy.
|
|
132
|
+
Density matrices currently use adaptive estimates instead.
|
|
133
|
+
|
|
134
|
+
The guarantee assumes a valid `curvature_bound`. Omitting it, `None`, and
|
|
135
|
+
`0.0` all assert zero curvature; none disables certification. See the
|
|
136
|
+
[mathematics guide][mathematics] for the proof and error bounds.
|
|
137
|
+
|
|
138
|
+
## API at a glance
|
|
139
|
+
|
|
140
|
+
- `SpectralMesh`: accept a callable or tight-binding dictionary and own the
|
|
141
|
+
adaptive geometry and cached eigensystems.
|
|
142
|
+
- `certify_simplex`: certify supplied vertex eigenpairs directly; eigenvalues
|
|
143
|
+
must be finite and ascending, and eigenvector columns must be finite and
|
|
144
|
+
orthonormal. These performance-sensitive numerical preconditions are not
|
|
145
|
+
rechecked.
|
|
146
|
+
- `mesh.integrate_charge`: adaptive filling and $dQ/d\mu$.
|
|
147
|
+
- `mesh.integrate_density_matrix`: real-space density-matrix components.
|
|
148
|
+
- `mesh.fermi_surface`: band-labelled points and cells in reduced coordinates.
|
|
149
|
+
|
|
150
|
+
Adaptive controls such as `target_error`, `max_refinements`, and
|
|
151
|
+
`preview_depth` are ordinary keyword arguments on the calculation that uses
|
|
152
|
+
them—there is no separate options object. Charge calculations default to
|
|
153
|
+
`preview_depth=0` because their sampled projected-error estimate drives
|
|
154
|
+
refinement intrinsically; positive depths are intended for explicit
|
|
155
|
+
diagnostic comparisons.
|
|
156
|
+
|
|
157
|
+
See the [visual Python tour][visual-tour], runnable
|
|
158
|
+
[quick start][quick-start], and
|
|
159
|
+
[two-band plotting example][fermi-example], the
|
|
160
|
+
[visual-generation notes][visuals], and the
|
|
161
|
+
[build and architecture guide][development].
|
|
162
|
+
|
|
163
|
+
## Development
|
|
164
|
+
|
|
165
|
+
AdaptiveSimplex provides the mesh geometry, refinement, vertex caching, and
|
|
166
|
+
cut-simplex integration; FermiSimplex adds the spectral models, certificates,
|
|
167
|
+
and observable-specific algorithms.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
pixi run test
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
This builds the standalone C++ library, verifies an installed downstream CMake
|
|
174
|
+
consumer, rebuilds the Python extension, and runs the Python tests. The dense
|
|
175
|
+
60-band stress case lives in [benchmarks/fermi_surface_60.py][stress-benchmark].
|
|
176
|
+
|
|
177
|
+
FermiSimplex is licensed under the BSD 3-Clause license. If you use it in
|
|
178
|
+
research, please cite the metadata in [CITATION.cff][citation].
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
[visual-tour]: https://github.com/Kostusas/FermiSimplex/blob/main/docs/showcase.md
|
|
182
|
+
[mathematics]: https://github.com/Kostusas/FermiSimplex/blob/main/docs/mathematics.md
|
|
183
|
+
[quick-start]: https://github.com/Kostusas/FermiSimplex/blob/main/examples/quick_start.py
|
|
184
|
+
[fermi-example]: https://github.com/Kostusas/FermiSimplex/blob/main/examples/fermi_surface.py
|
|
185
|
+
[visuals]: https://github.com/Kostusas/FermiSimplex/blob/main/docs/visuals.md
|
|
186
|
+
[development]: https://github.com/Kostusas/FermiSimplex/blob/main/docs/development.md
|
|
187
|
+
[stress-benchmark]: https://github.com/Kostusas/FermiSimplex/blob/main/benchmarks/fermi_surface_60.py
|
|
188
|
+
[citation]: https://github.com/Kostusas/FermiSimplex/blob/main/CITATION.cff
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from importlib.metadata import version
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
import fermisimplex
|
|
10
|
+
from fermisimplex import SpectralMesh
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_installed_distribution_runs_a_native_surface_calculation():
|
|
14
|
+
def hamiltonian(kx, ky):
|
|
15
|
+
coordinate_sum = kx + ky
|
|
16
|
+
return np.diag(
|
|
17
|
+
[coordinate_sum - 1.5, coordinate_sum - 0.5]
|
|
18
|
+
).astype(complex)
|
|
19
|
+
|
|
20
|
+
surface = SpectralMesh(hamiltonian).fermi_surface(
|
|
21
|
+
mu=0.0,
|
|
22
|
+
min_feature_size=0.2,
|
|
23
|
+
curvature_bound=0.0,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
assert version("FermiSimplex")
|
|
27
|
+
assert surface.completed
|
|
28
|
+
assert surface.coverage_certified
|
|
29
|
+
assert set(surface.cell_bands.tolist()) == {0, 1}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_bundled_openblas_notice_matches_platform_backend():
|
|
33
|
+
package_dir = Path(fermisimplex.__file__).resolve().parent
|
|
34
|
+
notice = package_dir / "licenses" / "scipy-openblas32.txt"
|
|
35
|
+
|
|
36
|
+
if sys.platform == "darwin":
|
|
37
|
+
assert not notice.exists()
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
assert notice.is_file()
|
|
41
|
+
assert "OpenBLAS" in notice.read_text()
|