Data Pipeline#
AtomicGraph: the one data object#
Every model consumes an AtomicGraph,
a dataclass holding one structure or a batch:
graph.pos # (N, 3) positions
graph.atomic_numbers # (N,)
graph.edge_index # (2, E) neighbor pairs [src, dst] within the cutoff
graph.cell_shifts # (E, 3) integer periodic image shift per edge
graph.batch # (N,) structure index per atom
graph.n_atoms # (B,)
graph.cell, graph.pbc # (B, 3, 3), (B, 3); None for molecules
graph.energy, graph.forces, graph.stress # targets, optional
graph.dipole, graph.polarizability # (B, 3), (B, 3, 3) targets, optional
graph.charges # (N,) partial-charge targets, optional
graph.total_charge, graph.spin_multiplicity # (B,), optional; neutral / closed shell if None
graph.weight, graph.head # (B,) loss weight and readout head, optional
graph.energy_weight, graph.force_weight, graph.stress_weight # (B,) term weights, optional
graph.atom_force_weight # (N,) per-atom force weight, optional
edge_vectors() computes
pos[dst] - pos[src] + cell_shift @ cell differentiably, which is where
periodicity lives: models never see the difference between a molecule and a
crystal, and forces and stress follow by autograd.
Structure dictionaries#
The input format is a plain dictionary per structure:
{
"pos": ..., # (N, 3), required
"atomic_numbers": ..., # (N,), required
"cell": ..., "pbc": ..., # (3, 3), (3,): periodic systems
"energy": ..., # scalar target
"forces": ..., # (N, 3) target
"stress": ..., # (3, 3) target
"dipole": ..., # (3,) target, e Angstrom; optional
"polarizability": ..., # (3, 3) target, Angstrom^3; optional
"charges": ..., # (N,) partial charges, e; optional (HDNNP 3G / 4G)
"total_charge": 0.0, # or "charge"; optional
"spin_multiplicity": 1, # optional
"weight": 1.0, # per-structure loss weight, optional
"energy_weight": 1.0, # or force_weight / stress_weight: one term only, optional
"atom_force_weight": ..., # (N,) weight of each atom's force error, optional
}
The weights are explained in Weight Energy and Force Labels.
Datasets and batching#
AtomicDataset converts each dictionary to
a graph at a cutoff and caches it. collate()
concatenates graphs into one batched graph, which the trainer uses as its
collate_fn:
from xnn.common.data import AtomicDataset, collate
ds = AtomicDataset(structures, cutoff=5.0)
batch = collate([ds[0], ds[1], ds[2]]) # one AtomicGraph holding 3 structures
A batch may mix molecules and cells, and structures with and without energy, force, stress, dipole or charge labels: the missing labels are masked out of the loss.
Files#
Any format ASE can read loads in one line (ase extra). Energies, forces
and stress are picked up from the frames; stress is converted from Voigt to
a full matrix:
ds = AtomicDataset.from_file("trajectory.extxyz", cutoff=5.0)
ds = AtomicDataset.from_file("dft.extxyz", cutoff=5.0,
energy_key="REF_energy", forces_key="REF_forces") # other key names
ds = AtomicDataset.from_atoms(list_of_atoms, cutoff=5.0)
Positions need not be wrapped into the cell. The converters
load_structures() and
atoms_to_structure() are public as well;
per-atom charges are read from atoms.arrays["charges"], the loss
weights weight / energy_weight / force_weight / stress_weight
from atoms.info and atom_force_weight from atoms.arrays.
RuNNer input.data files (bohr, hartree) read into structure dictionaries
in Angstrom and eV, with reference charges and the total charge:
from xnn.common.data.runner_io import read_runner_data, write_runner_data
structures = read_runner_data("input.data")
write_runner_data(structures, "copy.data")
Neighbor lists#
build_neighbor_list() builds the edges
and image shifts for molecular and periodic structures alike:
from xnn.common.data import build_neighbor_list
edge_index, cell_shifts = build_neighbor_list(pos, 5.0, cell=cell, pbc=pbc)
The built-in implementation is brute force and quadratic in the atom count.
With the vesin extra installed its cell list is used automatically, with
the same edges and conventions; on 5000 atoms at a 6 Å cutoff that is a
thousandfold faster. Geometry is kept in float64 whatever the model dtype.
The data hub#
Standard benchmark datasets download, convert and cache in one call:
from xnn.common.data import load_dataset, list_datasets
list_datasets()
splits = load_dataset("rmd17", molecule="aspirin") # {"train": [...], "test": [...]}
train = load_dataset("rmd17", molecule="aspirin", split="train", cutoff=5.0) # AtomicDataset
rmd17: revised MD17, ten molecules with PBE energies and forces. Optionsmolecule,fold(1 to 5),split,units(eVorkcal/mol),n_train/n_test.qm7: the 7165 QM7 molecules with PBE0 atomization energies and the stratified five-fold split (needs scipy).ethanol_response: 10,000 ethanol conformations at PBE0/def2-TZVP with energies, forces, dipole moments and polarizability tensors, the data of the PaiNN spectra (needs ase). Optionsn_train/n_val/n_test(8000 / 1000 / 1000),seed,units,shielding.ani1: the ANI-1 set, 20 M conformations of H/C/N/O molecules in one 4.8 GB archive. Optionsheavy_atoms(1 to 8),max_molecules,max_conformations,split,units.ani1x: the ANI-1x set, 5 M conformations with energies and forces (5.6 GB). Optionslevel(wb97x_dz,wb97x_tz,ccsd(t)_cbs),forces, and the caps and splits ofani1.ani1ccx: the coupled-cluster subset of ANI-1x (energies only), from the same file.ani2x: the seven-element ANI-2x set (H/C/N/O/S/F/Cl) with energies and forces (3.7 GB). Optionsn_atoms,forces,max_groups,max_conformations,split,units.hdnnp4g: the four charge-transfer benchmarks of the 4G-HDNNP paper with energies, forces and Hirshfeld charges, as oneallsplit (needs ase). Optionsystem:carbon_chain,ag_clusters,nacl_clusters,au2_mgo(periodic) orau2_mgo_minima(its four DFT-optimized structures). The molecular sets and the minima are CC BY-NC 4.0.spookynet_states: the electronic-state sets of the SpookyNet paper, 2200 Ag3+ / Ag3- clusters or singlet / triplet CH2 molecules at GFN2-xTB with total charges, spin multiplicities, energies, forces and dipoles. Optionssystem(ag3orcarbene),n_train/n_val(1000 / 100, the rest istest),seed.argon_md: periodic argon with energies, forces and stress, bundled with the repository; used by the argon example notebooks.lode_dimers: the LODE non-bonded sets (biomolecular dimers, monomers, point charges, xenon). Optionssubset,label,return_info; the bundledbio_scansubset loads offline.s22/s66: the S22 and S66 noncovalent dimers at their reference geometries with per-atomfragmentlabels and CCSD(T)/CBSinteraction_energy(kcal/mol). Optionreference(originalor, for S22,revised).
Files are cached and MD5-verified under datasets/<name>/ (cache_dir,
XNN_DATASETS or XNN_CACHE change that). The ANI sets need the hub
extra. Download an Upstream Dataset has examples per dataset;
Extending xnn shows how to register a new one.