Skip to content

Tips¤

Cache your compiles¤

The suite and any iterative workflow are compile-dominated on first run. A persistent compilation cache makes repeats compute-bound:

export JAX_COMPILATION_CACHE_DIR=~/.cache/dftax-xla-cache

It caches XLA's output, not the Python tracing that produces the program, so it removes some of the build and not all of it: coronene/def2-svp with density fitting builds in 286 s cold and 198 s against a warm cache (35 MB of entries) on an A100. Reuse needs the same shapes, so it pays off across repeated runs of one system (geometry optimization, conformer batches) rather than across different molecules.

It is worth setting when your molecule mixes contraction lengths, which in practice means any second-row element (S, P, Cl) beside first-row ones. The integral kernels are compiled per shell class, and such a molecule needs more distinct classes than a first-row-only one of the same size: penicillin G at cc-pVDZ compiles in 655 s against 353 s for the one-class-per-angular-triple partition it replaced. That buys the memory the build is actually capped by, 20.3 GiB of scratch down to 12.4, and the compile is paid once per shape.

Pick the Coulomb backend by system size¤

Exact ERI for small molecules and as the RI-free reference; df(...) from a few dozen atoms; add chunk= (and screen=1e-10) when the nao²×naux tensor stops fitting; mesh() to spread the materialized tensors across GPUs. The backend table has the crossovers.

Stream big grids¤

becke(..., chunk=20_000) keeps XC memory at O(chunk·nao); the materialized AO grid (and its jacobian, under grad) is usually the first thing to OOM on GPU for large systems. Forces honor the chunk too.

GPUs: pin devices and memory¤

JAX preallocates on every visible GPU. Per run:

CUDA_VISIBLE_DEVICES=0 XLA_PYTHON_CLIENT_MEM_FRACTION=0.5 python run.py

Use mesh() when you actually want all of them; a one-device mesh is a no-op.

Batched runs: keep only what you need¤

scf_batched returns energies/forces by default; orbital-sized fields are O(B·nspin·nao²) device memory and opt-in via return_orbitals=True. With several GPUs, scf_batched(..., mesh=mesh()) gives conformer data-parallelism with independent per-device convergence.

Property grids can be lighter¤

Finite-difference Hessians/spectra re-solve at every displacement; the benchmark-validated grid=becke(60, 194) is usually enough and much cheaper than the default (75×302 on C-F, 50×302 on H).