fastatomstruct 2.0.0__cp39-abi3-win_amd64.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.
- fastatomstruct/__init__.py +143 -0
- fastatomstruct/__init__.pyi +133 -0
- fastatomstruct/_pjrt/__init__.py +185 -0
- fastatomstruct/_quantity.py +2441 -0
- fastatomstruct/active_learning/__init__.py +76 -0
- fastatomstruct/active_learning/ase_bridge.py +110 -0
- fastatomstruct/active_learning/checkpoint.py +214 -0
- fastatomstruct/active_learning/committee.py +123 -0
- fastatomstruct/active_learning/config.py +602 -0
- fastatomstruct/active_learning/data.py +272 -0
- fastatomstruct/active_learning/dataset.py +206 -0
- fastatomstruct/active_learning/devices.py +123 -0
- fastatomstruct/active_learning/dft.py +151 -0
- fastatomstruct/active_learning/dft_queue.py +766 -0
- fastatomstruct/active_learning/events.py +43 -0
- fastatomstruct/active_learning/logging_utils.py +56 -0
- fastatomstruct/active_learning/md_components.py +313 -0
- fastatomstruct/active_learning/runners/__init__.py +0 -0
- fastatomstruct/active_learning/runners/_base.py +509 -0
- fastatomstruct/active_learning/runners/md.py +3695 -0
- fastatomstruct/active_learning/runners/pool.py +191 -0
- fastatomstruct/active_learning/runners/relaxation.py +248 -0
- fastatomstruct/active_learning/runners/rss.py +123 -0
- fastatomstruct/active_learning/trainer.py +1071 -0
- fastatomstruct/analysis.pyi +4918 -0
- fastatomstruct/bonding.pyi +428 -0
- fastatomstruct/build.pyi +377 -0
- fastatomstruct/calc.pyi +856 -0
- fastatomstruct/curve_editor/__init__.py +24 -0
- fastatomstruct/curve_editor/editor.py +1004 -0
- fastatomstruct/curve_editor/export.py +91 -0
- fastatomstruct/curve_editor/io_json.py +125 -0
- fastatomstruct/curve_editor/presets.py +92 -0
- fastatomstruct/curve_editor/units.py +31 -0
- fastatomstruct/elph.pyi +961 -0
- fastatomstruct/fastatomstruct.pyd +4 -0
- fastatomstruct/fastatomstruct.pyi +10370 -0
- fastatomstruct/io.pyi +803 -0
- fastatomstruct/kubo_greenwood_transport.pyi +212 -0
- fastatomstruct/mace_export.py +614 -0
- fastatomstruct/mace_foundation.py +38 -0
- fastatomstruct/mace_jax_backend.py +522 -0
- fastatomstruct/mace_rust_backend.py +168 -0
- fastatomstruct/mace_rust_train.py +118 -0
- fastatomstruct/md.pyi +1734 -0
- fastatomstruct/nald.pyi +126 -0
- fastatomstruct/optical_spectrum.pyi +391 -0
- fastatomstruct/optimizers.pyi +136 -0
- fastatomstruct/phonon.pyi +346 -0
- fastatomstruct/plotting.py +989 -0
- fastatomstruct/py.typed +0 -0
- fastatomstruct/queue.pyi +374 -0
- fastatomstruct/transport.py +611 -0
- fastatomstruct/ui.py +105 -0
- fastatomstruct/units.pyi +2315 -0
- fastatomstruct/viewer.pyi +368 -0
- fastatomstruct-2.0.0.dist-info/METADATA +211 -0
- fastatomstruct-2.0.0.dist-info/RECORD +63 -0
- fastatomstruct-2.0.0.dist-info/WHEEL +4 -0
- fastatomstruct-2.0.0.dist-info/licenses/ADDITIONAL-PERMISSIONS.md +26 -0
- fastatomstruct-2.0.0.dist-info/licenses/LICENSE +674 -0
- fastatomstruct-2.0.0.dist-info/licenses/THIRD-PARTY-NOTICES.md +83 -0
- fastatomstruct-2.0.0.dist-info/sboms/fastatomstruct-python.cyclonedx.json +19768 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from .fastatomstruct import *
|
|
4
|
+
|
|
5
|
+
# ── units: Quantity type + unit registry, built from the Rust unit table ────
|
|
6
|
+
# ``fs.units`` becomes the unit namespace: ``fs.units.fs`` is the unit, so
|
|
7
|
+
# ``2 * fs.units.fs`` is a ``Quantity``; the ASE-style float constants move
|
|
8
|
+
# to ``fs.units.ase``, the registry is ``fs.units.u``. Everything is
|
|
9
|
+
# built from ``fs.units.units_table()``, which mirrors
|
|
10
|
+
# ``fastatomstruct_core::units::quantities::UNITS`` — the single source of
|
|
11
|
+
# truth for symbols, factors and dimensions.
|
|
12
|
+
from ._quantity import attach_to_units_module as _attach_units # noqa: E402
|
|
13
|
+
|
|
14
|
+
_attach_units(globals().get("units"))
|
|
15
|
+
|
|
16
|
+
# ── Convenience re-exports of the most common entry points. ────────────────
|
|
17
|
+
# The canonical location of each name is still the submodule; the aliases
|
|
18
|
+
# below are only there so quick scripts and notebooks stay compact. New
|
|
19
|
+
# symbols should not be added here lightly — submodules are the default.
|
|
20
|
+
#
|
|
21
|
+
# Every alias is guarded so a wheel that was built without the relevant
|
|
22
|
+
# optional Cargo feature (``mace``, ``cp2k``, ``io``, ``md``, …) still
|
|
23
|
+
# imports cleanly — the missing name simply doesn't appear at the top level.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _alias(submodule_name: str, *names: str) -> None:
|
|
27
|
+
"""Bind ``fastatomstruct.<name>`` for every ``name`` in *names*, picking
|
|
28
|
+
each one from ``fastatomstruct.<submodule_name>``. Anything missing
|
|
29
|
+
(submodule or attribute) is silently skipped so the import never blows
|
|
30
|
+
up because of an optional Cargo feature."""
|
|
31
|
+
submodule = globals().get(submodule_name)
|
|
32
|
+
if submodule is None:
|
|
33
|
+
return
|
|
34
|
+
for name in names:
|
|
35
|
+
attr = getattr(submodule, name, None)
|
|
36
|
+
if attr is not None:
|
|
37
|
+
globals()[name] = attr
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _get_exported_names() -> list[str]:
|
|
41
|
+
"""Return a list of public names exported at the top level."""
|
|
42
|
+
return [n for n in globals() if not n.startswith("_")]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _is_available(name: str) -> bool:
|
|
46
|
+
"""Check whether *name* is exported at the top level."""
|
|
47
|
+
return name in globals()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Verbs.
|
|
51
|
+
_alias("viewer", "view", "view_many", "view_interactive", "view_image")
|
|
52
|
+
_alias("io", "open", "read", "write")
|
|
53
|
+
_alias("md", "run_molecular_dynamics")
|
|
54
|
+
_alias("optimizers", "run_optimization")
|
|
55
|
+
|
|
56
|
+
# Calculators.
|
|
57
|
+
_alias(
|
|
58
|
+
"calc",
|
|
59
|
+
"LennardJones",
|
|
60
|
+
"EmtCalculator",
|
|
61
|
+
"ACECalculator",
|
|
62
|
+
"MACECalculator",
|
|
63
|
+
"CP2KCalculator",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# MD building blocks — integrator + standard thermostats + standard barostats.
|
|
67
|
+
_alias(
|
|
68
|
+
"md",
|
|
69
|
+
"VelocityVerlet",
|
|
70
|
+
"LangevinIntegrator",
|
|
71
|
+
"NoThermostat",
|
|
72
|
+
"BerendsenThermostat",
|
|
73
|
+
"BussiThermostat",
|
|
74
|
+
"NoseHooverThermostat",
|
|
75
|
+
"AndersenThermostat",
|
|
76
|
+
"NoBarostat",
|
|
77
|
+
"BussiBarostat",
|
|
78
|
+
"SemiIsotropicBussiBarostat",
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Optimizer building blocks.
|
|
82
|
+
_alias(
|
|
83
|
+
"optimizers",
|
|
84
|
+
"FireOptimizer",
|
|
85
|
+
"LbfgsbOptimizer",
|
|
86
|
+
"BfgsOptimizer",
|
|
87
|
+
"NagOptimizer",
|
|
88
|
+
"ConvergenceCriteria",
|
|
89
|
+
"CellConstraint",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Phonon — only the three most frequently typed entry points stay at top
|
|
93
|
+
# level. Everything else lives at ``fs.phonon.*``.
|
|
94
|
+
_alias("phonon", "calculate_force_constants", "BandPath", "ForceConstants")
|
|
95
|
+
|
|
96
|
+
# NEGF electron-transport workflows (CP2K + SMEAGOL via cp2k_rs).
|
|
97
|
+
# Pure Python; imported as a submodule so `fs.transport` works. cp2k_rs is
|
|
98
|
+
# only required when a workflow actually runs, not at import time.
|
|
99
|
+
from . import transport # noqa: F401
|
|
100
|
+
|
|
101
|
+
# Plotting helpers (matplotlib-backed)
|
|
102
|
+
# These are pure-Python utilities shipped with the package.
|
|
103
|
+
# Every plotting helper is re-exported at the top level, because that is how
|
|
104
|
+
# they are used everywhere: docs, examples and tests write `fs.plot_dos(...)`,
|
|
105
|
+
# never `fs.plotting.plot_dos(...)`. Only three of the ten used to be listed
|
|
106
|
+
# here, so `fs.plot_cohp` — which docs/examples/cohp_coop.rst and
|
|
107
|
+
# docs/functions/bonding/index.rst both call — raised AttributeError.
|
|
108
|
+
from .plotting import (
|
|
109
|
+
plot_absorption_reflectivity,
|
|
110
|
+
plot_band_structure,
|
|
111
|
+
plot_band_structure_and_dos,
|
|
112
|
+
plot_cohp,
|
|
113
|
+
plot_dos,
|
|
114
|
+
plot_epsilon_complex,
|
|
115
|
+
plot_icohp_bars,
|
|
116
|
+
plot_n_kappa,
|
|
117
|
+
plot_optical_spectrum,
|
|
118
|
+
plot_sigma_complex,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
from .active_learning import run_active_learning_md
|
|
123
|
+
except ImportError:
|
|
124
|
+
import logging as _logging
|
|
125
|
+
|
|
126
|
+
_logging.getLogger(__name__).warning(
|
|
127
|
+
"active_learning requires numpy, ase, and mace-torch; "
|
|
128
|
+
"run_active_learning_md will not be available. "
|
|
129
|
+
"Install with: pip install fastatomstruct[mace-torch]",
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Interactive curve editor for temperature/pressure profiles (matplotlib).
|
|
133
|
+
# Pure-Python; attaches itself to the ``md`` submodule if available.
|
|
134
|
+
try:
|
|
135
|
+
from .curve_editor import curve_editor as _curve_editor_func
|
|
136
|
+
|
|
137
|
+
_md_mod = globals().get("md")
|
|
138
|
+
if _md_mod is not None:
|
|
139
|
+
setattr(_md_mod, "curve_editor", _curve_editor_func)
|
|
140
|
+
# The top-level name ``curve_editor`` is always the subpackage (as the stub says); without
|
|
141
|
+
# the ``md`` feature use ``from fastatomstruct.curve_editor import curve_editor``.
|
|
142
|
+
except ImportError:
|
|
143
|
+
pass # numpy or submodule not available
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# This file is generated by gen_stub.py -- do not edit by hand.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
This type stub file was generated by pyright.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .fastatomstruct import *
|
|
8
|
+
from .fastatomstruct import (
|
|
9
|
+
AoMatrixCsrResult as AoMatrixCsrResult,
|
|
10
|
+
AoMatrixResult as AoMatrixResult,
|
|
11
|
+
Atom as Atom,
|
|
12
|
+
Atoms as Atoms,
|
|
13
|
+
AtomsIterator as AtomsIterator,
|
|
14
|
+
BandStructureResult as BandStructureResult,
|
|
15
|
+
BuildOptions as BuildOptions,
|
|
16
|
+
CutoffMode as CutoffMode,
|
|
17
|
+
CylindricalAxis as CylindricalAxis,
|
|
18
|
+
DomainDecomposition as DomainDecomposition,
|
|
19
|
+
ElectronDensityResult as ElectronDensityResult,
|
|
20
|
+
Element as Element,
|
|
21
|
+
EnergyComponents as EnergyComponents,
|
|
22
|
+
FilterAnd as FilterAnd,
|
|
23
|
+
FilterElement as FilterElement,
|
|
24
|
+
FilterIndices as FilterIndices,
|
|
25
|
+
FilterNot as FilterNot,
|
|
26
|
+
FilterOr as FilterOr,
|
|
27
|
+
FilterPosition as FilterPosition,
|
|
28
|
+
FilterTag as FilterTag,
|
|
29
|
+
FixAtoms as FixAtoms,
|
|
30
|
+
GenericParticle as GenericParticle,
|
|
31
|
+
GridInfo as GridInfo,
|
|
32
|
+
HomoLumoResult as HomoLumoResult,
|
|
33
|
+
LatticeParameters as LatticeParameters,
|
|
34
|
+
LatticeType as LatticeType,
|
|
35
|
+
MoCoefficientsResult as MoCoefficientsResult,
|
|
36
|
+
NeighbourMode as NeighbourMode,
|
|
37
|
+
NeighbourSelectionCriteria as NeighbourSelectionCriteria,
|
|
38
|
+
QuantumATKDataType as QuantumATKDataType,
|
|
39
|
+
ReadIndex as ReadIndex,
|
|
40
|
+
ScfInfo as ScfInfo,
|
|
41
|
+
TimeAxis as TimeAxis,
|
|
42
|
+
Trajectory as Trajectory,
|
|
43
|
+
TrajectoryChunks as TrajectoryChunks,
|
|
44
|
+
TrajectoryIterator as TrajectoryIterator,
|
|
45
|
+
VDOSMethod as VDOSMethod,
|
|
46
|
+
VacfMethod as VacfMethod,
|
|
47
|
+
analysis as analysis,
|
|
48
|
+
bonding as bonding,
|
|
49
|
+
build as build,
|
|
50
|
+
calc as calc,
|
|
51
|
+
convert_ase as convert_ase,
|
|
52
|
+
disable_telemetry as disable_telemetry,
|
|
53
|
+
elph as elph,
|
|
54
|
+
enable_telemetry as enable_telemetry,
|
|
55
|
+
fetch_cp2k_worker as fetch_cp2k_worker,
|
|
56
|
+
filter_indices as filter_indices,
|
|
57
|
+
finalize_mpi as finalize_mpi,
|
|
58
|
+
get_mpi_status as get_mpi_status,
|
|
59
|
+
get_num_threads as get_num_threads,
|
|
60
|
+
init_mpi as init_mpi,
|
|
61
|
+
io as io,
|
|
62
|
+
is_log_enabled as is_log_enabled,
|
|
63
|
+
kubo_greenwood_transport as kubo_greenwood_transport,
|
|
64
|
+
md as md,
|
|
65
|
+
nald as nald,
|
|
66
|
+
optical_spectrum as optical_spectrum,
|
|
67
|
+
optimizers as optimizers,
|
|
68
|
+
phonon as phonon,
|
|
69
|
+
queue as queue,
|
|
70
|
+
read_obs_log as read_obs_log,
|
|
71
|
+
run_active_learning_md as run_active_learning_md,
|
|
72
|
+
run_dd_md as run_dd_md,
|
|
73
|
+
set_log_enabled as set_log_enabled,
|
|
74
|
+
set_num_threads as set_num_threads,
|
|
75
|
+
suppress_telemetry_notice as suppress_telemetry_notice,
|
|
76
|
+
units as units,
|
|
77
|
+
viewer as viewer,
|
|
78
|
+
)
|
|
79
|
+
from .viewer import (
|
|
80
|
+
view as view,
|
|
81
|
+
view_image as view_image,
|
|
82
|
+
view_interactive as view_interactive,
|
|
83
|
+
view_many as view_many,
|
|
84
|
+
)
|
|
85
|
+
from .io import open as open, read as read, write as write
|
|
86
|
+
from .md import (
|
|
87
|
+
AndersenThermostat as AndersenThermostat,
|
|
88
|
+
BerendsenThermostat as BerendsenThermostat,
|
|
89
|
+
BussiBarostat as BussiBarostat,
|
|
90
|
+
BussiThermostat as BussiThermostat,
|
|
91
|
+
LangevinIntegrator as LangevinIntegrator,
|
|
92
|
+
NoBarostat as NoBarostat,
|
|
93
|
+
NoThermostat as NoThermostat,
|
|
94
|
+
NoseHooverThermostat as NoseHooverThermostat,
|
|
95
|
+
SemiIsotropicBussiBarostat as SemiIsotropicBussiBarostat,
|
|
96
|
+
VelocityVerlet as VelocityVerlet,
|
|
97
|
+
run_molecular_dynamics as run_molecular_dynamics,
|
|
98
|
+
)
|
|
99
|
+
from .optimizers import (
|
|
100
|
+
BfgsOptimizer as BfgsOptimizer,
|
|
101
|
+
CellConstraint as CellConstraint,
|
|
102
|
+
ConvergenceCriteria as ConvergenceCriteria,
|
|
103
|
+
FireOptimizer as FireOptimizer,
|
|
104
|
+
LbfgsbOptimizer as LbfgsbOptimizer,
|
|
105
|
+
NagOptimizer as NagOptimizer,
|
|
106
|
+
run_optimization as run_optimization,
|
|
107
|
+
)
|
|
108
|
+
from .calc import (
|
|
109
|
+
ACECalculator as ACECalculator,
|
|
110
|
+
CP2KCalculator as CP2KCalculator,
|
|
111
|
+
EmtCalculator as EmtCalculator,
|
|
112
|
+
LennardJones as LennardJones,
|
|
113
|
+
MACECalculator as MACECalculator,
|
|
114
|
+
)
|
|
115
|
+
from .phonon import (
|
|
116
|
+
BandPath as BandPath,
|
|
117
|
+
ForceConstants as ForceConstants,
|
|
118
|
+
calculate_force_constants as calculate_force_constants,
|
|
119
|
+
)
|
|
120
|
+
from .plotting import (
|
|
121
|
+
plot_absorption_reflectivity as plot_absorption_reflectivity,
|
|
122
|
+
plot_band_structure as plot_band_structure,
|
|
123
|
+
plot_band_structure_and_dos as plot_band_structure_and_dos,
|
|
124
|
+
plot_cohp as plot_cohp,
|
|
125
|
+
plot_dos as plot_dos,
|
|
126
|
+
plot_epsilon_complex as plot_epsilon_complex,
|
|
127
|
+
plot_icohp_bars as plot_icohp_bars,
|
|
128
|
+
plot_n_kappa as plot_n_kappa,
|
|
129
|
+
plot_optical_spectrum as plot_optical_spectrum,
|
|
130
|
+
plot_sigma_complex as plot_sigma_complex,
|
|
131
|
+
)
|
|
132
|
+
from . import curve_editor, transport
|
|
133
|
+
from .active_learning import run_active_learning_md
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""XLA runtime libraries (PJRT plugins) for the Rust MACE backend.
|
|
2
|
+
|
|
3
|
+
The libraries are large and optional:
|
|
4
|
+
|
|
5
|
+
* CPU: the companion package ``fastatomstruct-xla-cpu``
|
|
6
|
+
(``pip install "fastatomstruct[xla]"``)
|
|
7
|
+
* CUDA: Google's CUDA 13 plugin ``jax-cuda13-pjrt`` (the XLA build of JAX)
|
|
8
|
+
and NVIDIA's CUDA 13 pip packages (``pip install "fastatomstruct[cuda13]"``),
|
|
9
|
+
in the versions verified against the MACE reference tests
|
|
10
|
+
|
|
11
|
+
:func:`plugin_path` finds whichever is installed, :func:`cueq_libraries` the
|
|
12
|
+
optional cuEquivariance kernels. For development,
|
|
13
|
+
``scripts/fetch_pjrt.py`` can instead place the pinned builds in this
|
|
14
|
+
directory (wheels built afterwards ship them). Nothing here imports jax.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import ctypes
|
|
20
|
+
import importlib
|
|
21
|
+
import os
|
|
22
|
+
from importlib import metadata
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
_HERE = Path(__file__).resolve().parent
|
|
26
|
+
_NAMES = {"cpu": "libpjrt_cpu.so", "cuda": "libpjrt_cuda.so"}
|
|
27
|
+
_ENV = {"cpu": "MACE_PJRT_PLUGIN", "cuda": "MACE_PJRT_CUDA_PLUGIN"}
|
|
28
|
+
_CPU_COMPANION = "fastatomstruct_xla_cpu"
|
|
29
|
+
|
|
30
|
+
#: The distribution that ships the CUDA plugin, and the plugin inside it.
|
|
31
|
+
CUDA_PLUGIN_DISTRIBUTION = "jax-cuda13-pjrt"
|
|
32
|
+
_CUDA_PLUGIN_FILE = "jax_plugins/xla_cuda13/xla_cuda_plugin.so"
|
|
33
|
+
# CUDA libraries the plugin opens by soname, by NVIDIA package, in loading
|
|
34
|
+
# order (the list of jax_plugins.xla_cuda13). The plugin's RPATH finds them
|
|
35
|
+
# in a standard site-packages layout as well; loading them first also covers
|
|
36
|
+
# the plugin and NVIDIA's packages in different site directories.
|
|
37
|
+
_CUDA_PRELOAD = (
|
|
38
|
+
("cu13", ("libcudart.so.13",)),
|
|
39
|
+
("cu13", ("libnvrtc.so.13",)),
|
|
40
|
+
("cu13", ("libcublas.so.13", "libcublasLt.so.13")),
|
|
41
|
+
("nccl", ("libnccl.so.2",)),
|
|
42
|
+
("cu13", ("libcupti.so.13",)),
|
|
43
|
+
("cu13", ("libcusparse.so.12",)),
|
|
44
|
+
("cu13", ("libcusolver.so.12",)),
|
|
45
|
+
("cu13", ("libcufft.so.12",)),
|
|
46
|
+
("nvshmem", ("libnvshmem_host.so.3",)),
|
|
47
|
+
("cudnn", ("libcudnn.so.9",)),
|
|
48
|
+
)
|
|
49
|
+
_CUDA_REQUIRED = ("libcudart.so.13", "libcublas.so.13")
|
|
50
|
+
_cuda_loaded: list[ctypes.CDLL] = []
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _cpu_companion() -> str | None:
|
|
54
|
+
try:
|
|
55
|
+
module = importlib.import_module(_CPU_COMPANION)
|
|
56
|
+
except ImportError:
|
|
57
|
+
return None
|
|
58
|
+
return module.library_path()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _cuda_plugin() -> str | None:
|
|
62
|
+
"""The plugin of the installed ``jax-cuda13-pjrt``, with NVIDIA's
|
|
63
|
+
libraries loaded first; ``None`` if it is not installed."""
|
|
64
|
+
try:
|
|
65
|
+
dist = metadata.distribution(CUDA_PLUGIN_DISTRIBUTION)
|
|
66
|
+
except metadata.PackageNotFoundError:
|
|
67
|
+
return None
|
|
68
|
+
path = Path(str(dist.locate_file(_CUDA_PLUGIN_FILE))).resolve()
|
|
69
|
+
if not path.is_file():
|
|
70
|
+
raise FileNotFoundError(
|
|
71
|
+
f"{path} is missing from {CUDA_PLUGIN_DISTRIBUTION}; reinstall "
|
|
72
|
+
'"fastatomstruct[cuda13]"'
|
|
73
|
+
)
|
|
74
|
+
_preload_cuda()
|
|
75
|
+
return str(path)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _nvidia_root() -> Path | None:
|
|
79
|
+
try:
|
|
80
|
+
dist = metadata.distribution("nvidia-cuda-runtime")
|
|
81
|
+
except metadata.PackageNotFoundError:
|
|
82
|
+
return None
|
|
83
|
+
return Path(str(dist.locate_file("nvidia"))).resolve()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _preload_cuda() -> None:
|
|
87
|
+
"""Load the CUDA libraries from NVIDIA's pip packages into the process,
|
|
88
|
+
as ``jax_plugins.xla_cuda13`` does before it registers the plugin.
|
|
89
|
+
|
|
90
|
+
Libraries a package does not ship are skipped (the plugin opens optional
|
|
91
|
+
ones itself or does without); the CUDA runtime and cuBLAS must be there.
|
|
92
|
+
XLA finds ``nvvm/libdevice`` and ``ptxas`` in ``nvidia/cu13`` on its own.
|
|
93
|
+
"""
|
|
94
|
+
if _cuda_loaded:
|
|
95
|
+
return
|
|
96
|
+
root = _nvidia_root()
|
|
97
|
+
found = set()
|
|
98
|
+
for package, names in _CUDA_PRELOAD:
|
|
99
|
+
for name in names:
|
|
100
|
+
path = None if root is None else root / package / "lib" / name
|
|
101
|
+
if path is None or not path.is_file():
|
|
102
|
+
continue
|
|
103
|
+
try:
|
|
104
|
+
_cuda_loaded.append(
|
|
105
|
+
ctypes.CDLL(str(path), mode=os.RTLD_NOW | os.RTLD_GLOBAL)
|
|
106
|
+
)
|
|
107
|
+
except OSError as exc:
|
|
108
|
+
raise OSError(f"could not load {path}: {exc}") from None
|
|
109
|
+
found.add(name)
|
|
110
|
+
missing = [name for name in _CUDA_REQUIRED if name not in found]
|
|
111
|
+
if missing:
|
|
112
|
+
_cuda_loaded.clear()
|
|
113
|
+
raise FileNotFoundError(
|
|
114
|
+
f"{missing} not found in NVIDIA's pip packages ({root}); "
|
|
115
|
+
'reinstall "fastatomstruct[cuda13]"'
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def plugin_path(device: str = "cpu") -> str | None:
|
|
120
|
+
"""Return the PJRT plugin for ``device`` (``'cpu'`` or ``'cuda'``).
|
|
121
|
+
|
|
122
|
+
Order: the device's environment variable, the installed runtime
|
|
123
|
+
(``fastatomstruct-xla-cpu`` / ``jax-cuda13-pjrt``), then a library placed
|
|
124
|
+
in this package. ``None`` if none exists.
|
|
125
|
+
"""
|
|
126
|
+
if device not in _NAMES:
|
|
127
|
+
raise ValueError(f"unknown device {device!r} (expected 'cpu' or 'cuda')")
|
|
128
|
+
env = os.environ.get(_ENV[device])
|
|
129
|
+
if env:
|
|
130
|
+
return env
|
|
131
|
+
installed = _cpu_companion() if device == "cpu" else _cuda_plugin()
|
|
132
|
+
if installed is not None:
|
|
133
|
+
return installed
|
|
134
|
+
bundled = _HERE / _NAMES[device]
|
|
135
|
+
return str(bundled) if bundled.is_file() else None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def library_dirs(device: str = "cpu") -> list[str]:
|
|
139
|
+
"""Directories with the shared libraries the plugin for ``device`` needs.
|
|
140
|
+
|
|
141
|
+
In this process :func:`plugin_path` loads them itself. A process that is
|
|
142
|
+
not Python (the domain decomposition workers) gets the directories on
|
|
143
|
+
``LD_LIBRARY_PATH``; the CUDA plugin also finds them through its RPATH.
|
|
144
|
+
"""
|
|
145
|
+
if device not in _NAMES:
|
|
146
|
+
raise ValueError(f"unknown device {device!r} (expected 'cpu' or 'cuda')")
|
|
147
|
+
if device == "cpu":
|
|
148
|
+
return []
|
|
149
|
+
root = _nvidia_root()
|
|
150
|
+
if root is None:
|
|
151
|
+
return []
|
|
152
|
+
return [str(p) for p in sorted(root.glob("*/lib")) if p.is_dir()]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def cueq_libraries(device: str = "cuda") -> list[str]:
|
|
156
|
+
"""The kernel library of NVIDIA cuEquivariance and what it depends on, in
|
|
157
|
+
loading order, from the installed packages ``cuequivariance-ops-jax`` and
|
|
158
|
+
``cuequivariance-ops`` (proprietary; fastatomstruct does not ship them)."""
|
|
159
|
+
import importlib.util
|
|
160
|
+
|
|
161
|
+
if device != "cuda":
|
|
162
|
+
raise ValueError(
|
|
163
|
+
"enable_cueq needs device='cuda' (the kernels are CUDA kernels)"
|
|
164
|
+
)
|
|
165
|
+
paths = []
|
|
166
|
+
for package, library in (
|
|
167
|
+
("cuequivariance_ops", "libcue_ops.so"),
|
|
168
|
+
("cuequivariance_ops_jax", "libcue_ops_jax.so"),
|
|
169
|
+
):
|
|
170
|
+
# (located without importing: the jax package would import jax)
|
|
171
|
+
spec = importlib.util.find_spec(package)
|
|
172
|
+
locations = list(getattr(spec, "submodule_search_locations", None) or [])
|
|
173
|
+
found = [
|
|
174
|
+
os.path.join(location, "lib", library)
|
|
175
|
+
for location in locations
|
|
176
|
+
if os.path.isfile(os.path.join(location, "lib", library))
|
|
177
|
+
]
|
|
178
|
+
if not found:
|
|
179
|
+
raise ValueError(
|
|
180
|
+
"enable_cueq needs NVIDIA's cuEquivariance kernels: "
|
|
181
|
+
"pip install cuequivariance-ops-jax-cu13 "
|
|
182
|
+
f"({library} of the package {package} was not found)"
|
|
183
|
+
)
|
|
184
|
+
paths.append(found[0])
|
|
185
|
+
return paths
|