Repository navigation
0.2.5 is a pre-1.0 release. Despite the patch-level version number it contains breaking changes, so if you pin aimnet~=0.2.0 (or >=0.2,<0.3), read the breaking-changes list below before upgrading.
Breaking changes
- Higher minimum dependency versions:
torch>=2.10(was 2.8),warp-lang>=1.13,<2(was 1.11), andnvalchemi-toolkit-ops>=0.4.1(was 0.3.1). Selecting PME Coulomb in an environment that still has nvalchemi-toolkit-ops 0.4.0 installed raisesRuntimeError. - Model loading and the artifact trust boundary: TorchScript is used only for
.jptfiles; a bare registry name takes precedence over a same-named implicit local path; registry SHA-256 digests must be lowercase; v2.ptartifacts are deserialized with weights and basic data only; inconsistent v2 metadata and incomplete weights are rejected; and model YAML may import only an exact, role-specific default set of classes and functions (no longer the wholetorch.nn.*namespace). Direct local and Hugging Face artifacts can extend that set or explicitly opt into unsafe loading for trusted custom code. Artifactmodel_yamlmay no longer use theptfileconstructor keyword or positionalargs, so a third-party artifact exported with positionalargsmust be re-exported. See the model-format migration notes. - Mode-2 neighbor matrices use global atom indices: batched
(B, N, M)matrices carryb * N + jwith the sentinelB * N, the last atom slot of every system must be a dummy (numbers[:, -1] == 0), and full-3D periodic inputs need aligned(B, N, M, 3)shifts. Matrices with per-system local indices are rejected; convert them withaimnet.nbops.convert_mode2_local_to_global. peratom_loss_fnnormalization: per-atom losses now average over real atoms in every neighbor mode. On padded batches the force loss is about 3-5x larger than before; divide the forces weight by about 3 to keep the old effective weighting.- Compilation options: passing
compile_kwargs={"fullgraph": False}is rejected (compiled inference always uses a full graph), andcompile_model=Trueon a legacy TorchScript.jptmodel raises instead of being ignored. - Derivatives of models with an embedded tabulated DFT-D3: Hessians, Hessian-vector products, and stress now raise
NotImplementedErrorfor a model that carriesaimnet.modules.DFTD3inside its own module tree. Previously they returned values that silently omitted the dispersion curvature and most of the dispersion virial. Registry models are not affected. - Removed APIs:
LRCoulomb.coul_ewaldandLRCoulomb.coul_pme(useLRCoulomb.forwardwithmethod="ewald"ormethod="pme"),aimnet.modules.core.DSequential,aimnet.constants.get_dftd3_param,aimnet.models.utils.has_dftd3_in_configand itsaimnet.modelsre-export,aimnet.train.utils.make_seed,aimnet.ops.lazy_calc_dij_lr, and the emptyaimnet.interfacespackage (import aimnet.interfacesnow fails). - Reused calculators return different, correct energies: in 0.1.0, 0.1.1, and 0.2.0 the adaptive neighbor list could silently drop neighbors after the calculator evaluated a sparser system, so a calculator reused across molecules or cells could return wrong energies and forces with no warning (#147). Results from such workflows change in this release; see the neighbor-list entry under Fixed.
Security
- Verified official model-registry downloads and cached artifacts against their SHA-256 digests before loading. Registry names and aliases now take precedence over same-named implicit local paths, preventing unverified local files from shadowing registry models. Official distributions currently bundle no model artifacts and continue to download them on demand.
- Restricted v2
.ptartifact deserialization to weights and basic data. Legacy.jptfiles are loaded only through the TorchScript loader and must come from a trusted source. - Validated Python class and function references in model YAML against a default trusted set. Direct local and Hugging Face artifacts can extend or replace that set, or explicitly select unsafe loading for trusted custom code; registry models always use the fixed default set.
- Enriched and structurally validated complete Hugging Face metadata before weight access, including unambiguous
SRCoulombparameter recovery. Registry-backed HF fallback now treats digest-verified registry YAML and metadata as authoritative and rejects conflicting family metadata. - Forbade the
ptfileconstructor kwarg anywhere in artifactmodel_yaml.DispParam.__init__runstorch.load(ptfile, weights_only=True)on a YAML-supplied path, and the import-path walker never inspected constructor kwargs, so a default-trusted artifact could carry an arbitrary-path read/probe/DoS primitive. The exporter always stripsptfilebefore an artifact is produced, so no legitimate artifact is affected; training-config loading is untouched. - Cross-checked D3TS presence between
model_yamland thehas_embedded_d3tsmetadata flag during artifact validation. Previously the two were validated independently, so a mislabeled artifact could silently double-count or entirely lose dispersion depending on which direction it was mislabeled. - Validated D3TS damping parameters (
a1,a2,s8,s6) supplied via artifactmodel_yaml: they must be finite, non-negative real numbers. These are plain constructor floats outside the state dict, so nothing previously stopped a NaN/Inf value ora1=a2=0(an undamped1/d**6collapse) from loading silently. - Forbade positional constructor arguments (
args) anywhere in artifactmodel_yaml.build_moduleforwards a siblingargslist intofunc(*args, **kwargs), but both constructor-argument guards match keyword names only, and the parameters they protect are not keyword-only:ptfileisDispParam's third positional parameter andD3TStakes its damping parameters first. A positional respelling therefore evaded both under the default trust policy —args: [null, null, <path>]reopened thetorch.loadarbitrary-path read/probe/DoS primitive (including a filesystem existence oracle via differing exception types) andargs: [-1.0, .nan, .inf]reopened the undamped1/d**6collapse. Artifactmodel_yamlis keyword-only in practice: no in-repo YAML and none of the shipped or registry-distributed artifacts useargs, so first-party and registry artifacts are unaffected, and rejecting the spelling outright makes the keyword guards sound rather than advisory. A third-party artifact that was exported with positionalargsbefore this change must be re-exported. Training-time construction never routes through this validator, so training configs may still useargs;aimnet exportdoes route the model YAML through it, so a training YAML that spells a module positionally fails at export with this message rather than at load. - Upgraded locked dependencies to clear every open Dependabot alert that has a released fix. All of these alerts were against
uv.lock, so they affect the development and CI environments, not whatpip install aimnetresolves. The locked torch moves from 2.9.1 to 2.14.1 (with triton 3.8.0), which clears thetorch.lstm_cellmemory-corruption advisory (fixed in 2.10) and thetorch.jit.scriptadvisory (fixed in 2.13). Pillow moves to 13.0.0, which fixes every open Pillow advisory. Development and transitive dependencies were moved to patched versions for certifi, GitPython, Mako, cryptography, idna, msgpack, mkdocs-material, pymdown-extensions, setuptools, tornado, urllib3, and virtualenv. The one remaining alert is a low-severity paramiko issue with no released patch, reached only as a test dependency through fabric and pysisyphus.
Added
- Added CUDA-graph inference replay for supported stock closed-shell GELU AIMNet2 models, with dense/sparse engines, optional Triton dense AEV kernels, per-layout numerical checks, bounded cache admission, mutation/storage guards, and regular-path fallback. Graph replay is opt-in: the
cuda_graphconstructor default isFalse, andcuda_graph=Nonedefers the choice to theAIMNET_CUDA_GRAPHenvironment variable.compile_model=Falseremains the default; passcuda_graph=Falseto benchmarktorch.compilealone. Requested replay that cannot apply (CPU,deterministic=True,mol_idx/cell/nbmatinput, stress/Hessian requests, unsupported models, ROCm) warns once per calculator and reason, andAIMNet2Calculator.clear_cuda_graphs()releases the captured graphs and their memory pool. Graph capture requiresnvalchemi-toolkit-ops>=0.5.0andwarp-lang>=1.16; with older versions installed the calculator warns and uses the regular path (the package floor stays atnvalchemi-toolkit-ops>=0.4.1). The optional Triton inference kernels (inference_kernels=True) require compute capability 8.0 or newer and otherwise use the equivalent PyTorch expressions. This does not accelerate training or add custom-model/legacy-artifact compatibility. - Added Hessians for every long-range Coulomb method and batched Hessians.
eval(..., hessian=True)now works with DSF, Ewald, and PME, which raised in 0.2.0; all three are relaxed-charge (they include the charge-response coupling), and Ewald and PME come from the calculator's total-energy autograd, so they are directly comparable for vibrational analysis while DSF still differs by its shifted-force truncation near the cutoff. A 3D batch(B, N, 3)or a flat input with a multi-moleculemol_idxis evaluated per structure and returns stacked(B, N, 3, N, 3)Hessians, or a list when the systems differ in size. The dense Hessian is returned in the force dtype (typically float32). DSF also supports force and stress training now, through the same differentiable torch path; in 0.2.0 it raised fortrain=Truewith forces or stress. - Added
AIMNet2Calculator.hessian_vector_product, a matrix-free Hessian-vector productH @ vfor one structure that avoids building the dense(3N, 3N)Hessian. It is exact reverse-mode autograd for every backend and returns float64 for Ewald and PME and the model dtype otherwise. Itsepsargument is deprecated and unused; passing it emits aDeprecationWarning. - Added compiled AIMNet2 training for energy and forces in neighbor modes 0, 1, and 2, and for stress in explicit-topology modes 1 and 2. Each process captures one symbolic derivative graph whose batch, atom, and neighbor dimensions remain dynamic; there is no application-level graph cache, and the original model remains the sole owner of parameters and checkpoint state.
- Added DDP support for compiled training. The derivative runner is wrapped before distributed setup so every forward passes through DDP, each rank owns its own compiled graph and may receive different local shapes, and unused derivative-only parameters are handled without bypassing gradient reduction.
- Added eager stress training through the same strain-derivative implementation used by compiled training and validation. Stress training requires a cell and aligned shift tensors for every explicit neighbor matrix; topology-free mode 0 stress is rejected. Labels are full
(B, 3, 3)tensors in eV/Å^3 with the ASE sign convention. The built-in loader yields dense batches, so stress training needs a custom dataset;aimnet trainchecks the first batch and stops early with an explanation. - Added
aimnet.calculators.vibrations, a numpy-only harmonic vibrational analysis of the calculator's dense Hessian.analyze_hessiansymmetrizes and mass-weights the(N, 3, N, 3)or(3N, 3N)Hessian, projects out rigid translations and rotations with an SVD-orthonormalized basis (three for a single atom, five for a linear molecule, six otherwise), diagonalizes only the vibrational subspace, and returns wavenumbers in cm^-1 with imaginary modes as negative values, vibrational quanta in eV, and unit-norm Cartesian normal modes;vibrational_analysis(calc, data)wraps thehessian=Trueevaluation for a single structure and warns when the model embeds a dispersion module whose curvature the Hessian currently omits. Unlikease.vibrations.VibrationsData, which does not project rigid-body motions, or the formersorted(freqs)[6:]recipe, which mishandled linear molecules and could hide an imaginary mode, the result is orientation-independent and correct for linear and near-linear geometries. Masses come from the bundledaimnet.constantstable, so no ASE install is required; the geometry-optimization tutorial's thermochemistry step now uses it. - Added an opt-in static geometry cache,
AIMNet2Calculator(..., cache_static=True), for repeated evaluations of the same resident CUDA geometry. It reuses calculator-built neighbor matrices and the external DFT-D3 energy and force terms; charge and multiplicity are not part of the cache key, so charge scans and similar workflows on one geometry reuse the geometry-dependent work while model outputs are recomputed. It applies to non-periodic single-system CUDA inputs only and is bypassed for Hessians, stress, training mode, and caller-suppliedmol_idxornbmat. - Added a manually invoked GPU validation tool for the torch / warp-lang / nvalchemi-toolkit-ops coupling, which CPU CI cannot cover.
make gpu-validatebuilds a resolver-coherent environment for each PyTorch version (2.10 through 2.14 by default), runs the GPU test suite, and diffs full-model energies and forces against a same-run baseline. Seedocs/gpu_validation.md. - Added
aimnet download <model...|--all>to prefetch registry model weights into the local cache for offline/HPC use. - Added
deterministic=Truecalculator option: routes external DFT-D3 and DSF Coulomb through their differentiable pure-torch paths, making repeated identical evaluations bitwise reproducible on the same machine/build (issue #93). This holds only on the dense CUDA layout (3D input with at mostnb_thresholdatoms per system, no cell, no Hessian) and for the same batch composition; on the packed neighbor-list layout, used abovenb_thresholdand for periodic systems, the calculator sorts the neighbor rows it builds (not a caller-suppliednbmat) into a canonical order, so energies are bitwise reproducible on CUDA whentorch.use_deterministic_algorithms(True)is also enabled (a one-time warning fires otherwise), while forces are not yet covered (issue #140). CPU always uses the packed layout and has been bitwise repeatable in testing, though that is not yet guaranteed. Ewald/PME kernels are not covered and warn once. - Added weekly and manually dispatched strict fleet CI covering every official registry digest, strict-policy artifact load, and exact role-specific YAML defaults.
- Added
aimnet inforeporting package/torch/warp versions, CUDA availability, registered kernel ops, and the model cache location. - Added a
weightspytest marker on modules that need model weights, enabling a verified fully-offline test run (-m "not weights ...") for packaging environments. - Added unit tests for the public
SizeGroupedDataset.save_h5,AIMNet2Calculator.set_lr_cutoff, andaimnet.train.loss.mse_loss_fnAPIs, which are kept. - Added targeted unit tests for previously untested code:
RegMultiMetric/regression_stats, theaimnet exporthelper functions (load_sae,bake_sae_into_model,mask_not_implemented_species),SizeGroupedDataset.cv_split/concatenate,train.utilsconfig/parameter helpers, andLRCoulombconstructor validation.
Changed
- Updated the supported Python and dependency range. Added Python 3.14 support: CI runs the core suite and the TorchSim tests on 3.14, and the
ase,hf, andtrainextras pass the default suite there too. Thesellaandpysisextras are not tested on 3.14, because the jaxlib version locked for them (0.5.3) has no Python 3.14 wheels; their CI lanes stay on Python 3.11. Legacy.jptmodels load on Python 3.14, but PyTorch marks TorchScript as unsupported there and emits aFutureWarning. The supported PyTorch range is 2.10 through 2.14 (raised from 2.8, see Breaking changes): CI runs the core suite against each of those versions on CPU, and the GPU path is validated across the same range withmake gpu-validate. The lockfile used for development and CI now resolves torch 2.14.1, triton 3.8.0, warp-lang 1.18.0, nvalchemi-toolkit-ops 0.5.0, numpy 2.4.6 (Python 3.11) and 2.5.4 (Python 3.12+), ase 3.29.0, torch-sim-atomistic 0.6.2, pytorch-ignite 0.5.5, and huggingface-hub 2.3.0. MkDocs is capped below 2.0 in the docs dependency group, because mkdocs-material does not support MkDocs 2. - BREAKING: Raised the minimum supported PyTorch version to 2.10. The Torch 2.9 singleton-only sum and broadcast branches were removed. Compiled mode-1 reductions now use the ordinary scatter/gather calculation with unreachable padding rows that prevent singleton-buffer corruption on PyTorch 2.12 without changing any returned value.
torch.compileis now a net speedup instead of a slowdown. The compiled model went from 42 graphs with 41 breaks to 4 graphs with 3 breaks by removingTensor.item()host syncs and other dynamo-unfriendly patterns from the compiled path; on an L40S a compiled energy-and-forces call is about 1.6-1.9x faster than eager, where it was previously slower. Eager results are bit-for-bit unchanged. The CPU backend keeps one protective graph break to avoid an inductor fusion bug in PyTorch releases before 2.11.- Compiled inference now always requests a full graph. Passing
compile_kwargs={"fullgraph": False}is rejected so graph breaks cannot silently weaken the requested compilation path. - Hessian and Hessian-vector-product requests continue to use the original eager AIMNet2 module when compiled inference is enabled;
_compiled_forwardis only a callable referencing that same module and never replaces the model or duplicates its parameters. - BREAKING:
peratom_loss_fnnow computes mean squared error over real atoms (numbers != 0) in every neighbor mode. This makes padded mode 0 use the same per-atom normalization as modes 1 and 2. Mode-1 atom counts now ignore the final dummy atom and produce one count per molecule, and a dummy with its own molecule-index bucket is folded into the last molecule, so eager and compiled reductions agree. Because the default loader pads nearly every batch, the force loss is about 3-5x larger than before on padded batches (the old formula divided by 3N) and per-atom charge losses 1-1.6x; divide the forces weight by about 3 to reproduce the old effective weighting. The loss is now computed as a masked sum without a device-to-host sync. - Training steps with a non-finite loss or gradient are now skipped on every rank (no optimizer step), counted in
engine.state.skipped_steps(also logged to wandb astrain/skipped_steps, with the skipped step's NaN left out of the loss curve), and logged;TerminateOnNankeeps its end-of-epoch behavior. The check is one fused device-side reduction with a single host sync per step. - Requesting
compile_model=Truefor a legacy TorchScript.jptmodel now raises immediately. Legacy models remain usable without compilation rather than silently accepting an unused compile option. - BREAKING: Added canonical global packed mode 2 for batched sparse neighbor matrices.
(B, N, M)neighbor matrices now carry global atom indicesb * N + jwith the sentinelB * N, every system must reserve its final atom slot as a dummy (numbers[:, -1] == 0), and full-3D periodic inputs must supply aligned integral lattice shifts of shape(B, N, M, 3). Legacy 3D matrices with per-system local indices are rejected on every entry path; convert them withaimnet.nbops.convert_mode2_local_to_global. The converter does not add the dummy row, so a caller whose padded capacity was exactly filled must first extendcoord,numbers, and every neighbor matrix by one padded slot. Inputs are validated before any kernel runs (index bounds, per-system ownership, packed sentinel tails, shift alignment, finite coordinates, non-singular cells): once per plain evaluation, with a Hessian request on a batch validating the batch before the split and each subsystem once more, and a standalone model validating every call; the check traces undertorch.compilewithout graph breaks, and a violation surfaces on CUDA and in compiled code as a device-side assertion (RuntimeError), on eager CPU asValueError. Ewald estimates its splitting parameter and k-space cutoff per system and PME one parameter set per batch, both from the real atoms only, so a mode-2 energy matches the flat evaluation to rounding whatever the padding width, and a system made of dummy rows only contributes zero energy without influencing the others, provided it carries a non-singular cell (copy a real one into padded slots; a zero cell has no reciprocal lattice). A batch in which every system is dummy rows only is rejected, matching the flat path. A single(3, 3)or(1, 3, 3)cell shared by a batch is broadcast to every system, like a(3,)pbc; the pure-torch ConvSV fallback masks the features it gathers for excluded neighbor slots instead of relying on a pre-masked geometry tensor. Because mode-2 callers supply the neighbor lists,nbmat_coulombmust be built at the Ewald/PME real-space cutoff. The declared cutoff is checked against that estimate for whichever list the Coulomb sum resolved to, and a warning is raised when it is shorter or when no cutoff was declared at all; reusing the model's short-range list instead costs of order 1 eV and 0.1 eV/A in forces for a condensed-phase cell. The calculator accepts the additional optional keysnbmat_coulomb,nbmat_dftd3,shifts_coulomb,shifts_dftd3,cutoff_lr,cutoff_coulomb, andcutoff_dftd3. See the calculator docs section "Batched sparse neighbor matrices (mode 2)" for the contract and migration steps. - Migrated Ewald and PME Coulomb to the nvalchemi-toolkit-ops energy+autograd API. Inference forces and stress, force and stress training, dense Hessians, and Hessian-vector products all flow through the calculator's total-energy autograd. Ewald energies are bit-identical and forces and stress agree to kernel rounding (at most 2e-06 eV/A). This requires nvalchemi-toolkit-ops 0.4.1: on 0.4.0 an upstream composed-graph charge-gradient bug corrupts PME train-mode forces (max error 4.5 eV/A on a test crystal), so selecting PME on 0.4.0 raises
RuntimeError, because the dependency floor alone would not protect an already-installed environment. Neither method uses the upstream direct-output flags that nvalchemi-toolkit-ops 0.4 deprecated, so no upstreamDeprecationWarningis emitted. - BREAKING: Model loading now routes TorchScript only for
.jptfiles, gives bare registry names precedence over same-named implicit local paths, rejects inconsistent v2 metadata and incomplete weights, requires lowercase registry SHA-256 digests, and uses exact role-specific default YAML imports instead of the broadtorch.nn.*namespace. See the model-format migration notes for remedies. - Split artifact checks into envelope, structural, canonical-distribution, and effective-calculator validation. Structurally valid direct and complete custom HF artifacts may explicitly disable external Coulomb or dispersion, while registry, registry-backed HF, and exported artifacts retain canonical action-flag requirements.
- Made
aimnet exportvalidate canonical artifacts before atomically replacing the destination, preserve existing output on failure, record embedded D3TS metadata, and accept explicit trusted custom constructor paths through--model-import-path. - Marked legacy
.jptruntime metadata as embedded-LR while retaining format version 1 and embedded-module defaults. Consolidated v2 construction, state loading, and source-routing predicates without expanding the stable top-level models API. - A closed-shell model (one charge channel) now warns once per calculator instance when it receives
mult != 1. The ASE, PySisyphus, and TorchSim wrappers always passmult, so an open-shell request previously returned a closed-shell result with no signal. - The automatic switch from
simpletodsfCoulomb for periodic input is now scoped to that evaluation and restored afterward, even on error. Previously one periodic call permanently moved a gas-phase calculator off its trained full Coulomb. An explicitset_lrcoulomb_method()still persists. - Species validation is cached on the identity of the
numberstensor, removing a per-step device-to-host sync from MD and optimization loops; charge validation still runs on every call. The packed (mode 1) message-passing path no longer syncs to read the molecule count. - Model families are declared as data in
model_registry.yaml(per-family charge support and post-hoc D3(BJ) parameters, and an explicitfamily:for every model) instead of being parsed from model names and hard-coded in the calculator. - Hardened
make test: the parallel run now hides CUDA and caps per-worker threads (CUDA_VISIBLE_DEVICES="" OMP_NUM_THREADS=1); previously xdist workers either all initialized the first GPU (OOM on CUDA boxes) or oversubscribed the CPU with per-worker torch thread pools. A newmake test-gputarget runs the GPU-marked tests serially on CUDA. - Raised the
nvalchemi-toolkit-opsfloor to 0.4.1 (see the Ewald and PME migration above) andwarp-langto>=1.13,<2. Moving from nvalchemi-toolkit-ops 0.3.1 to 0.4 left energies, charges, and Hessians bit-identical; explicit force and virial outputs shift within float32 accumulation noise (max 6.7e-05 eV/A on a periodic system). - Replaced deprecated PyTorch calls:
enable_tf32usestorch.set_float32_matmul_precision, the trainer passesweights_only=Truetotorch.loadexplicitly, and the distance path usestorch.linalg.vector_norm(values and gradients identical). - Marked the expensive tail of the test suite (~60 test nodes ≥2 s each: torch.compile, model-format roundtrips, dense-Hessian/HVP comparisons, multi-model ASE runs) with the
slowmarker; the default CPU test run now completes in under two minutes. Runpytest -m slowfor the marked tail. The cheapest representative of each critical path (dense Hessian, HVP correctness, legacy.jptloading, torch.compile smoke) stays in the default set. - Silenced the spurious "Warp CUDA error 100" stderr line emitted at import on CPU-only hosts.
- Made optional-dependency install hints installer-neutral (conda equivalents where they exist; pysisyphus named directly since it is pip-only).
Fixed
- Restored batched calculator input with a single shared
chargeormult(scalar or one-element list) in neighbor mode 1, eager and compiled; the calculator broadcasts it per system and rejects any other length mismatch with aValueError. - Validation with
trainer.compile=Trueno longer retains the compiled derivative graph underno_grad. - Refused Hessians, Hessian-vector products, and stress for a model that carries a tabulated DFT-D3 module inside its own module tree, instead of returning a number that silently omits dispersion. That module's energy reaches autograd through a first-order-only
autograd.Function: its backward multiplies a saved, graph-free force tensor, so the second derivative is structurally zero, and it returns no gradient forcell, so the periodic image term never contributes. Measured against finite differences, the dispersion Hessian block was absent entirely and about 95% of the dispersion virial was lost, worth 1.68 GPa of pressure on a test crystal, with nothing raised. Energy and forces were always correct and are unaffected. No registry model is affected: dispersion is attached externally, the default artifact policy rejectsaimnet.modules.DFTD3as an untrusted import path, and the exporter strips it. Load a model so the calculator owns dispersion externally, or useD3TS, which differentiates correctly. - Detected an affected model by class rather than by the key its dispersion module sits under. The previous test asked whether anything was registered at
dftd3/d3bj, which warned forD3TSunder that key, where there is no defect, and stayed silent for aDFTD3under any other key, where there is. The newhas_embedded_tabulated_dftd3predicate tests the class;has_externalizable_dftd3keeps its key semantics, which are what neighbor-list sizing needs. The narrower warning added tovibrational_analysisis removed, superseded by the calculator refusing the operation with a remedy. - Fixed the adaptive neighbor list silently dropping neighbors, which made a reused calculator return different energies for the same geometry depending on what it had evaluated before.
AdaptiveNeighborListrelied onNeighborOverflowErrorto grow its buffer, but in matrix mode nvalchemiops never raises it: it reports the true count innum_neighborswhile returning onlymax_neighborscolumns, so the retry branch was unreachable and the trim toactual_maxwas a no-op on an already-truncated list. The shrink heuristic then fed an undersized buffer forward with no way back up, so any evaluation on a sparser system permanently capped every later one (measured: caffeine shifts by 7.8e-03 eV after one single-atom evaluation on the same calculator, and a periodic cell by +79.7 eV / 19.7 eV/A after one sparser evaluation; repeated calls on a truncated list were not even stable). The buffer now grows and rebuilds whenever the reported count exceeds the allocated width. The cluster-tile kernels that CUDA selects for fully periodic float32 input raise instead of truncating; that retry now also grows straight to the reported count with headroom instead of by 1.5x of the current width per attempt (12 rebuilds down to 1 on a 13,824-atom cell). Affects everyAdaptiveNeighborListuser -- the main, LR, Coulomb and dispersion lists -- on any path that reachesmake_nbmat(PBC, CPU, caller-suppliedmol_idx,N > nb_threshold, ornb_threshold=0). A freshly constructed calculator was correct only for systems within the initial density estimate of about 0.2 atoms/A^3 -- a 64-atom, 6.4 A periodic cell at a 5 A cutoff was truncated on its very first call -- and those first-call cases are fixed by the same branch; results that were already correct are unchanged. - Treated the module tree, not metadata, as ground truth when detecting embedded long-range modules, so an artifact whose metadata flag contradicts its own contents still gets a long-range neighbor list (issue #118, third pass). The previous fix consulted the module tree only when
metadata is None; a shipped solvation artifact carries a metadata dict declaringhas_embedded_lr=Falseandhas_embedded_d3ts=Falsewhile holding anoutputs.d3bjsubmodule, so the detection helper was correct and never reached —lrstayed False and every system abovenb_thresholdraisedKeyError: ['_dftd3', '_lr'](measured: 119 atoms works, 125 fails)._has_embedded_dispersioncarried the same gate, so correcting onlyhas_embedded_lrleftcutoff_lratinfand turned theKeyErrorinto a[125, 8.4e17]allocation overflow; both now inspect the module tree unconditionally. A wrong flag can only ever cause a missing long-range list, never a spurious one. Energies belownb_thresholdare unchanged bit-for-bit. Note the existingmodel_yaml/has_embedded_d3tsartifact cross-check does not catch this case, which carries a D3BJ rather than a D3TS module. - Excluded the local weight cache (
aimnet/calculators/assets/) from wheels and sdists explicitly, instead of relying on hatchling's.gitignorehandling. - Fixed embedded-LR models failing with
KeyError: nbmat_lron every flattened evaluation (molecules abovenb_thresholdon CUDA, any size on CPU, PBC, or Hessians): when metadata declaredhas_embedded_lrbut neither dispersion nor Coulomb could be identified, the calculator built no long-range neighbor list at all despite resolving an all-pairscutoff_lrfor exactly that case. The shared LR list is now built with that cutoff (issue #118). - Detected embedded long-range modules from the module tree for pre-metadata artifacts: a model carrying a D3TS, DFTD3/D3BJ, or LRCoulomb submodule but no metadata dict previously had
lr=False, so no LR neighbor list was built and flattened evaluations failed withKeyError: nbmat_lr(issue #118, reopened case). - Trusted the
aimnet.modules.lr.D3TSsubmodule spelling of the D3TS class in the default artifact allowlist, alongside the existingaimnet.modules.D3TSbarrel spelling. The loader machinery that detects D3TS by class name matches the "D3TS" substring regardless of spelling, so an artifact using this spelling was recognized as D3TS by the export layer but rejected by the exact-match allowlist. - Fixed
SizeGroupedDataset.mergeraisingKeyErroron every realistic dataset. The method iteratedfor k in other:, butSizeGroupedDatasetdefines__getitem__without__iter__, so the loop fell back to the legacy integer sequence protocol: it probesother[0],other[1], ... and stops only onIndexError. Since the mapping is keyed by group size (atom count), the first size missing from a gap-free run starting at 0 raisesKeyErrorinstead -- for the bundled test set, whose sizes start at 7, that is the very first probe. It now iteratesother.keys().DataGroup.merge,DataGroup.rename_key,DataGroup.to_dictandSizeGroupedDataset.rename_datakeyare unchanged and remain supported; all five are now covered by tests. - Fixed
DataGroup.cv_splitcorrupting cross-validation folds: building each fold's train split mutated the shared parts in place viacat(), so later folds contained duplicated samples and validation splits larger than the dataset. Folds are now built without mutating the shared parts. - Fixed a crash when torch has CUDA but warp-lang does not (possible with conda-forge variant packages): the AEV kernel gate now checks warp CUDA availability and falls back to the pure-torch path with a one-time warning.
- Fixed
ConvSVraising on float64 or mixed-dtype CUDA input: the Warp kernel is now used only when both operands are float32, and other inputs fall back to the einsum path (float64 on GPU matches CPU to 2e-13). - Fixed the Hugging Face registry fallback for a
config.jsonwithoutmodel_yamlormember_names. The old lookup compared an underscore-normalized slug against dash-separated registry keys, so it never matched and the documented fallback always raised; it now warns and falls back to the registry as documented.
Removed
- Removed unused
aimnet.train.utils.make_seedandaimnet.ops.lazy_calc_dij_lr. - Removed unused
LRCoulomb.coul_ewaldandLRCoulomb.coul_pmeconvenience wrappers; useLRCoulomb.forwardwithmethod="ewald"/"pme". - Removed unused
aimnet.modules.core.DSequentialandaimnet.constants.get_dftd3_param. - Removed unused
aimnet.models.utils.has_dftd3_in_config(and itsaimnet.modelsre-export). - Removed the empty
aimnet.interfacespackage. It held only a docstring and nothing referenced it; the calculator adapters live inaimnet.calculators.import aimnet.interfacesnow raisesImportError.
Documentation
- Documented CUDA-graph eligibility, defaults and
torch.compileprecedence, startup/cache-memory costs, differentiation and mutation contracts, dependency limits, and fair backend comparisons. - Documented the rxn dipole origin convention:
center_coord=Falseis origin-safe because the family is net-neutral-only; any future charged-system family must shipcenter_coord=True. - Documented offline/HPC installation (cache pre-seeding via
aimnet download,AIMNET_CACHE_DIR,WARP_CACHE_PATH) and the model weight hosting immutability policy. - Added the AIMNet2-2025 paper citation (DOI and BibTeX) to the README and the documentation home page, and linked the paper from the model documentation and guides.
- Documented the limits of
deterministic=True: the bitwise guarantee covers the dense CUDA layout, the packed layout needstorch.use_deterministic_algorithms(True)for energies, packed forces are not yet covered, and a caller-suppliednbmatis not reordered. - Documented a known limitation of
aimnet2andaimnet2_2025: two hydrogens on the same heavy atom that are compressed below an H–H distance of about 0.75 Å can collapse toward 0 Å into a spurious low-energy region. The model pages recommend rejecting starting geometries with any H–H distance below 0.8 Å and checking optimized geometries for H–H distances below 0.6 Å until the next model release (#139). - Documented that Hessians are outside the
deterministic=Truebitwise guarantee: thevmap-based dense Hessian varies by about 1e-5 eV/Ų between runs on CUDA, which is negligible for vibrational frequencies (#143).