diffpes 2026.3.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.
- diffpes/__init__.py +65 -0
- diffpes/inout/__init__.py +88 -0
- diffpes/inout/chgcar.py +459 -0
- diffpes/inout/doscar.py +248 -0
- diffpes/inout/eigenval.py +258 -0
- diffpes/inout/hdf5.py +818 -0
- diffpes/inout/helpers.py +295 -0
- diffpes/inout/kpoints.py +433 -0
- diffpes/inout/plotting.py +757 -0
- diffpes/inout/poscar.py +174 -0
- diffpes/inout/procar.py +331 -0
- diffpes/inout/py.typed +0 -0
- diffpes/maths/__init__.py +68 -0
- diffpes/maths/dipole.py +368 -0
- diffpes/maths/gaunt.py +496 -0
- diffpes/maths/spherical_harmonics.py +336 -0
- diffpes/py.typed +0 -0
- diffpes/radial/__init__.py +47 -0
- diffpes/radial/bessel.py +198 -0
- diffpes/radial/integrate.py +128 -0
- diffpes/radial/wavefunctions.py +335 -0
- diffpes/simul/__init__.py +146 -0
- diffpes/simul/broadening.py +258 -0
- diffpes/simul/crosssections.py +196 -0
- diffpes/simul/expanded.py +1021 -0
- diffpes/simul/forward.py +586 -0
- diffpes/simul/oam.py +112 -0
- diffpes/simul/polarization.py +443 -0
- diffpes/simul/py.typed +0 -0
- diffpes/simul/resolution.py +122 -0
- diffpes/simul/self_energy.py +142 -0
- diffpes/simul/spectrum.py +1116 -0
- diffpes/simul/workflow.py +424 -0
- diffpes/tightb/__init__.py +68 -0
- diffpes/tightb/diagonalize.py +340 -0
- diffpes/tightb/hamiltonian.py +286 -0
- diffpes/tightb/projections.py +134 -0
- diffpes/types/__init__.py +162 -0
- diffpes/types/aliases.py +52 -0
- diffpes/types/bands.py +1064 -0
- diffpes/types/dos.py +510 -0
- diffpes/types/geometry.py +306 -0
- diffpes/types/kpath.py +365 -0
- diffpes/types/params.py +496 -0
- diffpes/types/py.typed +0 -0
- diffpes/types/radial_params.py +482 -0
- diffpes/types/self_energy.py +271 -0
- diffpes/types/tb_model.py +531 -0
- diffpes/types/volumetric.py +608 -0
- diffpes/utils/__init__.py +30 -0
- diffpes/utils/math.py +255 -0
- diffpes/utils/py.typed +0 -0
- diffpes-2026.3.1.dist-info/METADATA +176 -0
- diffpes-2026.3.1.dist-info/RECORD +55 -0
- diffpes-2026.3.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"""Crystal geometry data structure for VASP crystal structures.
|
|
2
|
+
|
|
3
|
+
Extended Summary
|
|
4
|
+
----------------
|
|
5
|
+
Defines the :class:`CrystalGeometry` PyTree for representing
|
|
6
|
+
crystal structures parsed from VASP POSCAR files. Includes real-space
|
|
7
|
+
lattice vectors, reciprocal lattice, atomic coordinates, element
|
|
8
|
+
symbols, and atom counts per species.
|
|
9
|
+
|
|
10
|
+
Routine Listings
|
|
11
|
+
----------------
|
|
12
|
+
:class:`CrystalGeometry`
|
|
13
|
+
PyTree NamedTuple for crystal geometry data.
|
|
14
|
+
:func:`make_crystal_geometry`
|
|
15
|
+
Factory function with validation and reciprocal lattice computation.
|
|
16
|
+
|
|
17
|
+
Notes
|
|
18
|
+
-----
|
|
19
|
+
The ``symbols`` field is stored as auxiliary data in the PyTree
|
|
20
|
+
since JAX cannot trace Python strings. All numeric fields are
|
|
21
|
+
stored as JAX arrays for compatibility with JAX transformations.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import jax.numpy as jnp
|
|
25
|
+
from beartype import beartype
|
|
26
|
+
from beartype.typing import NamedTuple, Tuple, Union
|
|
27
|
+
from jax.tree_util import register_pytree_node_class
|
|
28
|
+
from jaxtyping import Array, Float, Int, jaxtyped
|
|
29
|
+
|
|
30
|
+
from .aliases import ScalarNumeric
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@register_pytree_node_class
|
|
34
|
+
class CrystalGeometry(NamedTuple):
|
|
35
|
+
"""PyTree for crystal geometry from VASP POSCAR.
|
|
36
|
+
|
|
37
|
+
Encapsulates the full crystal structure information parsed from a
|
|
38
|
+
VASP POSCAR file: real-space lattice vectors, the corresponding
|
|
39
|
+
reciprocal lattice, fractional atomic coordinates, per-species
|
|
40
|
+
element symbols, and per-species atom counts. Together these fields
|
|
41
|
+
fully describe the periodic crystal needed for ARPES simulation.
|
|
42
|
+
|
|
43
|
+
This class is registered as a JAX PyTree via
|
|
44
|
+
``@register_pytree_node_class``. Numeric fields (lattice,
|
|
45
|
+
reciprocal_lattice, coords, atom_counts) are stored as children
|
|
46
|
+
visible to JAX tracing, while the ``symbols`` tuple of Python
|
|
47
|
+
strings is stored as auxiliary data because JAX cannot trace
|
|
48
|
+
Python strings.
|
|
49
|
+
|
|
50
|
+
Attributes
|
|
51
|
+
----------
|
|
52
|
+
lattice : Float[Array, "3 3"]
|
|
53
|
+
Real-space lattice vectors as rows (angstroms).
|
|
54
|
+
reciprocal_lattice : Float[Array, "3 3"]
|
|
55
|
+
Reciprocal lattice vectors as rows (1/angstroms).
|
|
56
|
+
coords : Float[Array, "N 3"]
|
|
57
|
+
Fractional atomic coordinates.
|
|
58
|
+
symbols : tuple[str, ...]
|
|
59
|
+
Element symbols for each species.
|
|
60
|
+
atom_counts : Int[Array, " S"]
|
|
61
|
+
Number of atoms per species.
|
|
62
|
+
|
|
63
|
+
Notes
|
|
64
|
+
-----
|
|
65
|
+
Registered as a JAX PyTree with ``@register_pytree_node_class``.
|
|
66
|
+
The ``symbols`` field is a tuple of Python strings and therefore
|
|
67
|
+
must be stored as PyTree auxiliary data (not children). JAX treats
|
|
68
|
+
auxiliary data as compile-time constants: changing ``symbols``
|
|
69
|
+
triggers recompilation of any ``jit``-compiled function that
|
|
70
|
+
receives this PyTree.
|
|
71
|
+
|
|
72
|
+
See Also
|
|
73
|
+
--------
|
|
74
|
+
make_crystal_geometry : Factory function with validation, float64
|
|
75
|
+
casting, and automatic reciprocal lattice computation.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
lattice: Float[Array, "3 3"]
|
|
79
|
+
reciprocal_lattice: Float[Array, "3 3"]
|
|
80
|
+
coords: Float[Array, "N 3"]
|
|
81
|
+
symbols: tuple[str, ...]
|
|
82
|
+
atom_counts: Int[Array, " S"]
|
|
83
|
+
|
|
84
|
+
def tree_flatten(
|
|
85
|
+
self,
|
|
86
|
+
) -> Tuple[
|
|
87
|
+
Tuple[
|
|
88
|
+
Float[Array, "3 3"],
|
|
89
|
+
Float[Array, "3 3"],
|
|
90
|
+
Float[Array, "N 3"],
|
|
91
|
+
Int[Array, " S"],
|
|
92
|
+
],
|
|
93
|
+
tuple[str, ...],
|
|
94
|
+
]:
|
|
95
|
+
"""Flatten into JAX children and auxiliary data.
|
|
96
|
+
|
|
97
|
+
Separates the PyTree into children (JAX-traced arrays) and
|
|
98
|
+
auxiliary data (static Python values). For CrystalGeometry,
|
|
99
|
+
the four numeric fields are children and the ``symbols`` tuple
|
|
100
|
+
of strings is auxiliary data.
|
|
101
|
+
|
|
102
|
+
Implementation Logic
|
|
103
|
+
--------------------
|
|
104
|
+
1. **Children** (JAX arrays, participate in autodiff):
|
|
105
|
+
``(lattice, reciprocal_lattice, coords, atom_counts)``
|
|
106
|
+
2. **Auxiliary data** (static, not traced by JAX):
|
|
107
|
+
``symbols`` -- a tuple of Python strings. JAX treats this
|
|
108
|
+
as a compile-time constant; any change triggers JIT
|
|
109
|
+
recompilation.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
children : tuple of Array
|
|
114
|
+
Tuple of ``(lattice, reciprocal_lattice, coords,
|
|
115
|
+
atom_counts)`` JAX arrays.
|
|
116
|
+
aux_data : tuple[str, ...]
|
|
117
|
+
Element symbol strings, stored outside JAX tracing.
|
|
118
|
+
"""
|
|
119
|
+
return (
|
|
120
|
+
(
|
|
121
|
+
self.lattice,
|
|
122
|
+
self.reciprocal_lattice,
|
|
123
|
+
self.coords,
|
|
124
|
+
self.atom_counts,
|
|
125
|
+
),
|
|
126
|
+
self.symbols,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
@classmethod
|
|
130
|
+
def tree_unflatten(
|
|
131
|
+
cls,
|
|
132
|
+
aux_data: tuple[str, ...],
|
|
133
|
+
children: Tuple[
|
|
134
|
+
Float[Array, "3 3"],
|
|
135
|
+
Float[Array, "3 3"],
|
|
136
|
+
Float[Array, "N 3"],
|
|
137
|
+
Int[Array, " S"],
|
|
138
|
+
],
|
|
139
|
+
) -> "CrystalGeometry":
|
|
140
|
+
"""Reconstruct a CrystalGeometry from flattened components.
|
|
141
|
+
|
|
142
|
+
Inverse of :meth:`tree_flatten`. JAX calls this method
|
|
143
|
+
automatically when unflattening a PyTree after a
|
|
144
|
+
transformation (e.g., inside ``jax.jit`` or ``jax.grad``).
|
|
145
|
+
|
|
146
|
+
Implementation Logic
|
|
147
|
+
--------------------
|
|
148
|
+
1. Unpack ``children`` into four JAX arrays:
|
|
149
|
+
``(lattice, reciprocal_lattice, coords, atom_counts)``.
|
|
150
|
+
2. Receive ``aux_data`` as the ``symbols`` tuple of strings.
|
|
151
|
+
3. Pass all five fields to the constructor, re-interleaving
|
|
152
|
+
``symbols`` from ``aux_data`` into its correct position
|
|
153
|
+
between ``coords`` and ``atom_counts``.
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
aux_data : tuple[str, ...]
|
|
158
|
+
Element symbol strings recovered from auxiliary data.
|
|
159
|
+
children : tuple of Array
|
|
160
|
+
Tuple of ``(lattice, reciprocal_lattice, coords,
|
|
161
|
+
atom_counts)`` JAX arrays.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
geometry : CrystalGeometry
|
|
166
|
+
Reconstructed instance with identical data.
|
|
167
|
+
"""
|
|
168
|
+
lattice: Float[Array, "3 3"]
|
|
169
|
+
reciprocal_lattice: Float[Array, "3 3"]
|
|
170
|
+
coords: Float[Array, "N 3"]
|
|
171
|
+
atom_counts: Int[Array, " S"]
|
|
172
|
+
lattice, reciprocal_lattice, coords, atom_counts = children
|
|
173
|
+
geometry: CrystalGeometry = cls(
|
|
174
|
+
lattice=lattice,
|
|
175
|
+
reciprocal_lattice=reciprocal_lattice,
|
|
176
|
+
coords=coords,
|
|
177
|
+
symbols=aux_data,
|
|
178
|
+
atom_counts=atom_counts,
|
|
179
|
+
)
|
|
180
|
+
return geometry
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _compute_reciprocal_lattice(
|
|
184
|
+
lattice: Float[Array, "3 3"],
|
|
185
|
+
) -> Float[Array, "3 3"]:
|
|
186
|
+
r"""Compute reciprocal lattice vectors from real-space lattice.
|
|
187
|
+
|
|
188
|
+
Derives the reciprocal lattice from the real-space lattice using
|
|
189
|
+
the standard cross-product formula. The reciprocal lattice vectors
|
|
190
|
+
``b_i`` satisfy ``a_i . b_j = 2 pi delta_{ij}``.
|
|
191
|
+
|
|
192
|
+
Implementation Logic
|
|
193
|
+
--------------------
|
|
194
|
+
Given real-space lattice vectors ``a1, a2, a3`` (rows of
|
|
195
|
+
``lattice``):
|
|
196
|
+
|
|
197
|
+
1. **Extract rows**: ``a1 = lattice[0]``, ``a2 = lattice[1]``,
|
|
198
|
+
``a3 = lattice[2]``.
|
|
199
|
+
2. **Compute unit-cell volume**:
|
|
200
|
+
``V = a1 . (a2 x a3)`` (scalar triple product).
|
|
201
|
+
3. **Compute reciprocal vectors** via the cross-product formula:
|
|
202
|
+
|
|
203
|
+
.. math::
|
|
204
|
+
|
|
205
|
+
b_1 = 2\\pi \\, (a_2 \\times a_3) / V
|
|
206
|
+
|
|
207
|
+
b_2 = 2\\pi \\, (a_3 \\times a_1) / V
|
|
208
|
+
|
|
209
|
+
b_3 = 2\\pi \\, (a_1 \\times a_2) / V
|
|
210
|
+
|
|
211
|
+
4. **Stack** ``[b1, b2, b3]`` into a (3, 3) array with
|
|
212
|
+
reciprocal vectors as rows.
|
|
213
|
+
|
|
214
|
+
Parameters
|
|
215
|
+
----------
|
|
216
|
+
lattice : Float[Array, "3 3"]
|
|
217
|
+
Real-space lattice vectors as rows.
|
|
218
|
+
|
|
219
|
+
Returns
|
|
220
|
+
-------
|
|
221
|
+
reciprocal : Float[Array, "3 3"]
|
|
222
|
+
Reciprocal lattice vectors as rows (units of 1/angstrom,
|
|
223
|
+
with the 2 pi prefactor included).
|
|
224
|
+
"""
|
|
225
|
+
a1: Float[Array, " 3"] = lattice[0]
|
|
226
|
+
a2: Float[Array, " 3"] = lattice[1]
|
|
227
|
+
a3: Float[Array, " 3"] = lattice[2]
|
|
228
|
+
volume: Float[Array, " "] = jnp.dot(a1, jnp.cross(a2, a3))
|
|
229
|
+
b1: Float[Array, " 3"] = 2.0 * jnp.pi * jnp.cross(a2, a3) / volume
|
|
230
|
+
b2: Float[Array, " 3"] = 2.0 * jnp.pi * jnp.cross(a3, a1) / volume
|
|
231
|
+
b3: Float[Array, " 3"] = 2.0 * jnp.pi * jnp.cross(a1, a2) / volume
|
|
232
|
+
reciprocal: Float[Array, "3 3"] = jnp.stack([b1, b2, b3])
|
|
233
|
+
return reciprocal
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
@jaxtyped(typechecker=beartype)
|
|
237
|
+
def make_crystal_geometry(
|
|
238
|
+
lattice: Union[Float[Array, "3 3"], "list[list[ScalarNumeric]]"],
|
|
239
|
+
coords: Float[Array, "N 3"],
|
|
240
|
+
symbols: tuple[str, ...],
|
|
241
|
+
atom_counts: Union[Int[Array, " S"], "list[int]"],
|
|
242
|
+
) -> CrystalGeometry:
|
|
243
|
+
"""Create a validated CrystalGeometry instance.
|
|
244
|
+
|
|
245
|
+
Validates and normalises the inputs, then automatically computes
|
|
246
|
+
the reciprocal lattice from the real-space lattice so the caller
|
|
247
|
+
does not need to supply it. Numeric arrays are cast to the
|
|
248
|
+
appropriate JAX dtypes (float64 for real-valued fields, int32
|
|
249
|
+
for atom counts).
|
|
250
|
+
|
|
251
|
+
Implementation Logic
|
|
252
|
+
--------------------
|
|
253
|
+
1. **Cast lattice** to ``jnp.float64`` via ``jnp.asarray``.
|
|
254
|
+
Accepts both JAX arrays and nested Python lists.
|
|
255
|
+
2. **Cast coords** to ``jnp.float64`` via ``jnp.asarray``.
|
|
256
|
+
3. **Cast atom_counts** to ``jnp.int32`` via ``jnp.asarray``.
|
|
257
|
+
Accepts both JAX integer arrays and Python ``list[int]``.
|
|
258
|
+
4. **Auto-compute reciprocal lattice** by calling
|
|
259
|
+
``_compute_reciprocal_lattice(lattice_arr)``. This derives
|
|
260
|
+
``b_i = 2 pi (a_j x a_k) / V`` from the validated
|
|
261
|
+
real-space lattice.
|
|
262
|
+
5. **Construct** the ``CrystalGeometry`` NamedTuple from all
|
|
263
|
+
five fields (including the computed reciprocal lattice) and
|
|
264
|
+
return it.
|
|
265
|
+
|
|
266
|
+
Parameters
|
|
267
|
+
----------
|
|
268
|
+
lattice : Union[Float[Array, "3 3"], list]
|
|
269
|
+
Real-space lattice vectors as rows (angstroms).
|
|
270
|
+
coords : Float[Array, "N 3"]
|
|
271
|
+
Fractional atomic coordinates.
|
|
272
|
+
symbols : tuple[str, ...]
|
|
273
|
+
Element symbols for each species.
|
|
274
|
+
atom_counts : Union[Int[Array, " S"], list[int]]
|
|
275
|
+
Number of atoms per species.
|
|
276
|
+
|
|
277
|
+
Returns
|
|
278
|
+
-------
|
|
279
|
+
geometry : CrystalGeometry
|
|
280
|
+
Validated crystal geometry instance with the reciprocal
|
|
281
|
+
lattice pre-computed.
|
|
282
|
+
|
|
283
|
+
See Also
|
|
284
|
+
--------
|
|
285
|
+
CrystalGeometry : The PyTree class constructed by this factory.
|
|
286
|
+
_compute_reciprocal_lattice : Cross-product formula used to
|
|
287
|
+
derive the reciprocal lattice.
|
|
288
|
+
"""
|
|
289
|
+
lattice_arr: Float[Array, "3 3"] = jnp.asarray(lattice, dtype=jnp.float64)
|
|
290
|
+
coords_arr: Float[Array, "N 3"] = jnp.asarray(coords, dtype=jnp.float64)
|
|
291
|
+
counts_arr: Int[Array, " S"] = jnp.asarray(atom_counts, dtype=jnp.int32)
|
|
292
|
+
reciprocal: Float[Array, "3 3"] = _compute_reciprocal_lattice(lattice_arr)
|
|
293
|
+
geometry: CrystalGeometry = CrystalGeometry(
|
|
294
|
+
lattice=lattice_arr,
|
|
295
|
+
reciprocal_lattice=reciprocal,
|
|
296
|
+
coords=coords_arr,
|
|
297
|
+
symbols=symbols,
|
|
298
|
+
atom_counts=counts_arr,
|
|
299
|
+
)
|
|
300
|
+
return geometry
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
__all__: list[str] = [
|
|
304
|
+
"CrystalGeometry",
|
|
305
|
+
"make_crystal_geometry",
|
|
306
|
+
]
|
diffpes/types/kpath.py
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
"""K-point path information data structure.
|
|
2
|
+
|
|
3
|
+
Extended Summary
|
|
4
|
+
----------------
|
|
5
|
+
Defines the :class:`KPathInfo` PyTree for storing Brillouin-zone
|
|
6
|
+
metadata parsed from VASP KPOINTS files, including both plotting
|
|
7
|
+
labels and mode-specific metadata (automatic grids, explicit weights,
|
|
8
|
+
line-mode segments/endpoints).
|
|
9
|
+
|
|
10
|
+
Routine Listings
|
|
11
|
+
----------------
|
|
12
|
+
:class:`KPathInfo`
|
|
13
|
+
PyTree for k-point path metadata.
|
|
14
|
+
:func:`make_kpath_info`
|
|
15
|
+
Create a validated KPathInfo instance.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import jax.numpy as jnp
|
|
19
|
+
from beartype import beartype
|
|
20
|
+
from beartype.typing import NamedTuple, Optional, Tuple, Union
|
|
21
|
+
from jax.tree_util import register_pytree_node_class
|
|
22
|
+
from jaxtyping import Array, Float, Int, jaxtyped
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@register_pytree_node_class
|
|
26
|
+
class KPathInfo(NamedTuple):
|
|
27
|
+
"""PyTree for k-point path metadata.
|
|
28
|
+
|
|
29
|
+
Extended Summary
|
|
30
|
+
----------------
|
|
31
|
+
Stores Brillouin-zone path information parsed from VASP KPOINTS
|
|
32
|
+
files. Includes plotting fields (labels + label indices) and
|
|
33
|
+
mode-specific metadata needed for full parser completeness:
|
|
34
|
+
automatic-mode grid/shift, explicit-mode k-points/weights, and
|
|
35
|
+
line-mode segment endpoints.
|
|
36
|
+
|
|
37
|
+
This class is registered as a JAX PyTree via
|
|
38
|
+
``@register_pytree_node_class``. Array-valued metadata is stored
|
|
39
|
+
as children. String metadata is stored as auxiliary data because
|
|
40
|
+
JAX cannot trace Python strings.
|
|
41
|
+
|
|
42
|
+
Attributes
|
|
43
|
+
----------
|
|
44
|
+
num_kpoints : Int[Array, " "]
|
|
45
|
+
Total number of k-points in the path (line mode) or header
|
|
46
|
+
count (explicit mode).
|
|
47
|
+
label_indices : Int[Array, " L"]
|
|
48
|
+
Indices of symmetry points along the path.
|
|
49
|
+
points_per_segment : Int[Array, " "]
|
|
50
|
+
Raw integer from line 2 of KPOINTS (line mode: points per
|
|
51
|
+
segment).
|
|
52
|
+
segments : Int[Array, " "]
|
|
53
|
+
Number of line segments in line mode.
|
|
54
|
+
kpoints : Optional[Float[Array, "K 3"]]
|
|
55
|
+
Mode-specific k-points:
|
|
56
|
+
line mode -> segment endpoints (segments + 1),
|
|
57
|
+
explicit mode -> listed k-points,
|
|
58
|
+
automatic mode -> None.
|
|
59
|
+
weights : Optional[Float[Array, " K"]]
|
|
60
|
+
Explicit-mode per-k-point weights (None otherwise).
|
|
61
|
+
grid : Optional[Int[Array, " 3"]]
|
|
62
|
+
Automatic-mode Monkhorst-Pack/Gamma grid (None otherwise).
|
|
63
|
+
shift : Optional[Float[Array, " 3"]]
|
|
64
|
+
Automatic-mode grid shift (None otherwise).
|
|
65
|
+
mode : str
|
|
66
|
+
KPOINTS file mode (Automatic, Line-mode, Explicit).
|
|
67
|
+
labels : tuple[str, ...]
|
|
68
|
+
Symmetry point labels (e.g., Gamma, M, K).
|
|
69
|
+
comment : str
|
|
70
|
+
Raw comment from KPOINTS line 1.
|
|
71
|
+
coordinate_mode : str
|
|
72
|
+
Coordinate/scheme line metadata:
|
|
73
|
+
line/explicit -> Reciprocal/Cartesian line,
|
|
74
|
+
automatic -> scheme line (e.g., Monkhorst-Pack).
|
|
75
|
+
|
|
76
|
+
Notes
|
|
77
|
+
-----
|
|
78
|
+
Registered as a JAX PyTree with ``@register_pytree_node_class``.
|
|
79
|
+
The ``mode`` string and ``labels`` tuple of strings are stored as
|
|
80
|
+
auxiliary data (not children). JAX treats auxiliary data as
|
|
81
|
+
compile-time constants: changing either value triggers
|
|
82
|
+
recompilation of any ``jit``-compiled function that receives
|
|
83
|
+
this PyTree.
|
|
84
|
+
|
|
85
|
+
See Also
|
|
86
|
+
--------
|
|
87
|
+
make_kpath_info : Factory function with validation and int32
|
|
88
|
+
casting.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
num_kpoints: Int[Array, " "]
|
|
92
|
+
label_indices: Int[Array, " L"]
|
|
93
|
+
points_per_segment: Int[Array, " "]
|
|
94
|
+
segments: Int[Array, " "]
|
|
95
|
+
kpoints: Optional[Float[Array, "K 3"]]
|
|
96
|
+
weights: Optional[Float[Array, " K"]]
|
|
97
|
+
grid: Optional[Int[Array, " 3"]]
|
|
98
|
+
shift: Optional[Float[Array, " 3"]]
|
|
99
|
+
mode: str
|
|
100
|
+
labels: tuple[str, ...]
|
|
101
|
+
comment: str
|
|
102
|
+
coordinate_mode: str
|
|
103
|
+
|
|
104
|
+
def tree_flatten(
|
|
105
|
+
self,
|
|
106
|
+
) -> Tuple[
|
|
107
|
+
Tuple[
|
|
108
|
+
Int[Array, " "],
|
|
109
|
+
Int[Array, " L"],
|
|
110
|
+
Int[Array, " "],
|
|
111
|
+
Int[Array, " "],
|
|
112
|
+
Optional[Float[Array, "K 3"]],
|
|
113
|
+
Optional[Float[Array, " K"]],
|
|
114
|
+
Optional[Int[Array, " 3"]],
|
|
115
|
+
Optional[Float[Array, " 3"]],
|
|
116
|
+
],
|
|
117
|
+
Tuple[str, tuple[str, ...], str, str],
|
|
118
|
+
]:
|
|
119
|
+
"""Flatten into JAX children and auxiliary data.
|
|
120
|
+
|
|
121
|
+
Separates the PyTree into children (JAX-traced arrays) and
|
|
122
|
+
auxiliary data (static Python values). For KPathInfo, all
|
|
123
|
+
array-valued metadata is stored in children and string metadata
|
|
124
|
+
in aux_data.
|
|
125
|
+
|
|
126
|
+
Implementation Logic
|
|
127
|
+
--------------------
|
|
128
|
+
1. **Children** (JAX arrays, participate in tracing):
|
|
129
|
+
``(num_kpoints, label_indices, points_per_segment,
|
|
130
|
+
segments, kpoints, weights, grid, shift)``.
|
|
131
|
+
2. **Auxiliary data** (static, not traced by JAX):
|
|
132
|
+
``(mode, labels, comment, coordinate_mode)``.
|
|
133
|
+
JAX treats these as compile-time constants; any change
|
|
134
|
+
triggers JIT recompilation.
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
-------
|
|
138
|
+
children : tuple of Array
|
|
139
|
+
Tuple of array-valued metadata fields.
|
|
140
|
+
aux_data : tuple[str, tuple[str, ...], str, str]
|
|
141
|
+
String metadata stored outside JAX tracing.
|
|
142
|
+
"""
|
|
143
|
+
return (
|
|
144
|
+
(
|
|
145
|
+
self.num_kpoints,
|
|
146
|
+
self.label_indices,
|
|
147
|
+
self.points_per_segment,
|
|
148
|
+
self.segments,
|
|
149
|
+
self.kpoints,
|
|
150
|
+
self.weights,
|
|
151
|
+
self.grid,
|
|
152
|
+
self.shift,
|
|
153
|
+
),
|
|
154
|
+
(
|
|
155
|
+
self.mode,
|
|
156
|
+
self.labels,
|
|
157
|
+
self.comment,
|
|
158
|
+
self.coordinate_mode,
|
|
159
|
+
),
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
@classmethod
|
|
163
|
+
def tree_unflatten(
|
|
164
|
+
cls,
|
|
165
|
+
aux_data: Tuple[str, tuple[str, ...], str, str],
|
|
166
|
+
children: Tuple[
|
|
167
|
+
Int[Array, " "],
|
|
168
|
+
Int[Array, " L"],
|
|
169
|
+
Int[Array, " "],
|
|
170
|
+
Int[Array, " "],
|
|
171
|
+
Optional[Float[Array, "K 3"]],
|
|
172
|
+
Optional[Float[Array, " K"]],
|
|
173
|
+
Optional[Int[Array, " 3"]],
|
|
174
|
+
Optional[Float[Array, " 3"]],
|
|
175
|
+
],
|
|
176
|
+
) -> "KPathInfo":
|
|
177
|
+
"""Reconstruct a KPathInfo from flattened components.
|
|
178
|
+
|
|
179
|
+
Inverse of :meth:`tree_flatten`. JAX calls this method
|
|
180
|
+
automatically when unflattening a PyTree after a
|
|
181
|
+
transformation (e.g., inside ``jax.jit`` or ``jax.grad``).
|
|
182
|
+
|
|
183
|
+
Implementation Logic
|
|
184
|
+
--------------------
|
|
185
|
+
1. Unpack ``children`` into the eight array-valued fields.
|
|
186
|
+
2. Unpack ``aux_data`` into the four string fields.
|
|
187
|
+
3. Pass all fields to the constructor.
|
|
188
|
+
|
|
189
|
+
Parameters
|
|
190
|
+
----------
|
|
191
|
+
aux_data : tuple[str, tuple[str, ...], str, str]
|
|
192
|
+
String metadata recovered from auxiliary data.
|
|
193
|
+
children : tuple of Array
|
|
194
|
+
Array-valued metadata tuple.
|
|
195
|
+
|
|
196
|
+
Returns
|
|
197
|
+
-------
|
|
198
|
+
kpath : KPathInfo
|
|
199
|
+
Reconstructed instance with identical data.
|
|
200
|
+
"""
|
|
201
|
+
num_kpoints: Int[Array, " "]
|
|
202
|
+
label_indices: Int[Array, " L"]
|
|
203
|
+
points_per_segment: Int[Array, " "]
|
|
204
|
+
segments: Int[Array, " "]
|
|
205
|
+
kpoints: Optional[Float[Array, "K 3"]]
|
|
206
|
+
weights: Optional[Float[Array, " K"]]
|
|
207
|
+
grid: Optional[Int[Array, " 3"]]
|
|
208
|
+
shift: Optional[Float[Array, " 3"]]
|
|
209
|
+
(
|
|
210
|
+
num_kpoints,
|
|
211
|
+
label_indices,
|
|
212
|
+
points_per_segment,
|
|
213
|
+
segments,
|
|
214
|
+
kpoints,
|
|
215
|
+
weights,
|
|
216
|
+
grid,
|
|
217
|
+
shift,
|
|
218
|
+
) = children
|
|
219
|
+
mode: str
|
|
220
|
+
labels: tuple[str, ...]
|
|
221
|
+
comment: str
|
|
222
|
+
coordinate_mode: str
|
|
223
|
+
mode, labels, comment, coordinate_mode = aux_data
|
|
224
|
+
kpath: KPathInfo = cls(
|
|
225
|
+
num_kpoints=num_kpoints,
|
|
226
|
+
label_indices=label_indices,
|
|
227
|
+
points_per_segment=points_per_segment,
|
|
228
|
+
segments=segments,
|
|
229
|
+
kpoints=kpoints,
|
|
230
|
+
weights=weights,
|
|
231
|
+
grid=grid,
|
|
232
|
+
shift=shift,
|
|
233
|
+
mode=mode,
|
|
234
|
+
labels=labels,
|
|
235
|
+
comment=comment,
|
|
236
|
+
coordinate_mode=coordinate_mode,
|
|
237
|
+
)
|
|
238
|
+
return kpath
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@jaxtyped(typechecker=beartype)
|
|
242
|
+
def make_kpath_info( # noqa: PLR0913
|
|
243
|
+
num_kpoints: Union[int, Int[Array, " "]],
|
|
244
|
+
label_indices: Union[Int[Array, " L"], "list[int]"],
|
|
245
|
+
points_per_segment: Union[int, Int[Array, " "]] = 0,
|
|
246
|
+
segments: Union[int, Int[Array, " "]] = 0,
|
|
247
|
+
kpoints: Optional[Float[Array, "K 3"]] = None,
|
|
248
|
+
weights: Optional[Float[Array, " K"]] = None,
|
|
249
|
+
grid: Optional[Union[Int[Array, " 3"], "list[int]"]] = None,
|
|
250
|
+
shift: Optional[Float[Array, " 3"]] = None,
|
|
251
|
+
mode: str = "Line-mode",
|
|
252
|
+
labels: tuple[str, ...] = (),
|
|
253
|
+
comment: str = "",
|
|
254
|
+
coordinate_mode: str = "",
|
|
255
|
+
) -> KPathInfo:
|
|
256
|
+
"""Create a validated KPathInfo instance.
|
|
257
|
+
|
|
258
|
+
Extended Summary
|
|
259
|
+
----------------
|
|
260
|
+
Factory function that validates and normalises raw k-path
|
|
261
|
+
metadata before constructing a ``KPathInfo`` PyTree. Integer
|
|
262
|
+
scalars and arrays are cast to ``int32``; float arrays are cast
|
|
263
|
+
to ``float64``. Optional fields (``kpoints``, ``weights``,
|
|
264
|
+
``grid``, ``shift``) are cast only when present, preserving
|
|
265
|
+
``None`` for modes that do not use them.
|
|
266
|
+
|
|
267
|
+
The function is decorated with ``@jaxtyped(typechecker=beartype)``
|
|
268
|
+
so that shape constraints are checked at call time. String
|
|
269
|
+
metadata (``mode``, ``labels``, ``comment``, ``coordinate_mode``)
|
|
270
|
+
is passed through unchanged and stored as PyTree auxiliary data.
|
|
271
|
+
|
|
272
|
+
Use this factory when constructing ``KPathInfo`` from parsed
|
|
273
|
+
KPOINTS data or when building synthetic k-paths for testing. The
|
|
274
|
+
factory ensures consistent dtypes and handles the three KPOINTS
|
|
275
|
+
modes (Line-mode, Explicit, Automatic) through the optional
|
|
276
|
+
fields.
|
|
277
|
+
|
|
278
|
+
Implementation Logic
|
|
279
|
+
--------------------
|
|
280
|
+
1. **Cast integer fields** (``num_kpoints``, ``label_indices``,
|
|
281
|
+
``points_per_segment``, ``segments``) to ``jnp.int32`` via
|
|
282
|
+
``jnp.asarray``. Accepts both Python ints and JAX arrays.
|
|
283
|
+
2. **Cast optional float fields** (``kpoints``, ``weights``,
|
|
284
|
+
``shift``) to ``jnp.float64`` when not ``None``.
|
|
285
|
+
3. **Cast optional int field** (``grid``) to ``jnp.int32`` when
|
|
286
|
+
not ``None``.
|
|
287
|
+
4. **Pass string metadata** (``mode``, ``labels``, ``comment``,
|
|
288
|
+
``coordinate_mode``) through unchanged -- stored as auxiliary
|
|
289
|
+
data in the PyTree.
|
|
290
|
+
5. **Construct** the ``KPathInfo`` NamedTuple from all validated
|
|
291
|
+
fields and return it.
|
|
292
|
+
|
|
293
|
+
Parameters
|
|
294
|
+
----------
|
|
295
|
+
num_kpoints : Union[int, Int[Array, " "]]
|
|
296
|
+
Total number of k-points along the path.
|
|
297
|
+
label_indices : Union[Int[Array, " L"], list[int]]
|
|
298
|
+
Indices of symmetry points along the path.
|
|
299
|
+
points_per_segment : Union[int, Int[Array, " "]], optional
|
|
300
|
+
Raw value from line 2 of KPOINTS. Default is 0.
|
|
301
|
+
segments : Union[int, Int[Array, " "]], optional
|
|
302
|
+
Number of path segments in line mode. Default is 0.
|
|
303
|
+
kpoints : Optional[Float[Array, "K 3"]], optional
|
|
304
|
+
Mode-specific k-point coordinates. Default is None.
|
|
305
|
+
weights : Optional[Float[Array, " K"]], optional
|
|
306
|
+
Explicit-mode weights. Default is None.
|
|
307
|
+
grid : Optional[Union[Int[Array, " 3"], list[int]]], optional
|
|
308
|
+
Automatic-mode MP/Gamma grid. Default is None.
|
|
309
|
+
shift : Optional[Float[Array, " 3"]], optional
|
|
310
|
+
Automatic-mode grid shift. Default is None.
|
|
311
|
+
mode : str, optional
|
|
312
|
+
KPOINTS file mode. Default is ``"Line-mode"``.
|
|
313
|
+
labels : tuple[str, ...], optional
|
|
314
|
+
Symmetry point labels. Default is empty tuple.
|
|
315
|
+
comment : str, optional
|
|
316
|
+
KPOINTS comment line. Default is empty string.
|
|
317
|
+
coordinate_mode : str, optional
|
|
318
|
+
Coordinate/scheme line metadata. Default is empty string.
|
|
319
|
+
|
|
320
|
+
Returns
|
|
321
|
+
-------
|
|
322
|
+
kpath : KPathInfo
|
|
323
|
+
Validated k-path info instance.
|
|
324
|
+
|
|
325
|
+
See Also
|
|
326
|
+
--------
|
|
327
|
+
KPathInfo : The PyTree class constructed by this factory.
|
|
328
|
+
"""
|
|
329
|
+
nkpts_arr: Int[Array, " "] = jnp.asarray(num_kpoints, dtype=jnp.int32)
|
|
330
|
+
indices_arr: Int[Array, " L"] = jnp.asarray(label_indices, dtype=jnp.int32)
|
|
331
|
+
pps_arr: Int[Array, " "] = jnp.asarray(points_per_segment, dtype=jnp.int32)
|
|
332
|
+
segments_arr: Int[Array, " "] = jnp.asarray(segments, dtype=jnp.int32)
|
|
333
|
+
kpoints_arr: Optional[Float[Array, "K 3"]] = None
|
|
334
|
+
if kpoints is not None:
|
|
335
|
+
kpoints_arr = jnp.asarray(kpoints, dtype=jnp.float64)
|
|
336
|
+
weights_arr: Optional[Float[Array, " K"]] = None
|
|
337
|
+
if weights is not None:
|
|
338
|
+
weights_arr = jnp.asarray(weights, dtype=jnp.float64)
|
|
339
|
+
grid_arr: Optional[Int[Array, " 3"]] = None
|
|
340
|
+
if grid is not None:
|
|
341
|
+
grid_arr = jnp.asarray(grid, dtype=jnp.int32)
|
|
342
|
+
shift_arr: Optional[Float[Array, " 3"]] = None
|
|
343
|
+
if shift is not None:
|
|
344
|
+
shift_arr = jnp.asarray(shift, dtype=jnp.float64)
|
|
345
|
+
kpath: KPathInfo = KPathInfo(
|
|
346
|
+
num_kpoints=nkpts_arr,
|
|
347
|
+
label_indices=indices_arr,
|
|
348
|
+
points_per_segment=pps_arr,
|
|
349
|
+
segments=segments_arr,
|
|
350
|
+
kpoints=kpoints_arr,
|
|
351
|
+
weights=weights_arr,
|
|
352
|
+
grid=grid_arr,
|
|
353
|
+
shift=shift_arr,
|
|
354
|
+
mode=mode,
|
|
355
|
+
labels=labels,
|
|
356
|
+
comment=comment,
|
|
357
|
+
coordinate_mode=coordinate_mode,
|
|
358
|
+
)
|
|
359
|
+
return kpath
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
__all__: list[str] = [
|
|
363
|
+
"KPathInfo",
|
|
364
|
+
"make_kpath_info",
|
|
365
|
+
]
|