Skip to content

v2.0.0 — Correctness release

Choose a tag to compare

@Jamessfks Jamessfks released this 10 Aug 01:32

SimpleAtom v2.0 is a correctness release. The interface changed; what changed more is
whether you can trust the numbers.

SimpleAtom wraps MACE. The main risk in a wrapper is not
crashing — it is returning a plausible number for a calculation that never ran. v2.0 was
audited specifically for that failure mode and found six instances. Every one read as
correct code. None would have been caught by reviewing a diff.

Calculations now fail loudly instead of quietly returning the wrong thing

  • calculationType had no allow-list. The backend dispatched if geometry-opt / elif molecular-dynamics with no else, so any unrecognised type fell through to a
    single-point and came back labelled as whatever was requested. The API accepts arbitrary
    JSON, so {"calculationType":"phonon"} returned a single-point energy presented as a
    phonon run.
  • modelType had no allow-list. Selecting a custom model without uploading a checkpoint
    returned MACE-MP-0 results labelled custom — shareable and exportable, permanently
    attributing numbers to a model that was never loaded.
  • Both are now validated in the Python backend, which is the real boundary since the API is
    callable directly, and mirrored in the route handler as a fast 400.
  • Geometry optimisation reports whether it actually converged. BFGS.run()'s return
    value was discarded, so a run that exhausted maxOptSteps without reaching fmax was
    described as completed.
  • Results echo the parameters that actually ran — defaults resolved, CUDA→CPU fallback
    applied, the real dispersion state, and the precision read off the loaded model rather
    than the one requested.

Molecular dynamics is reproducible and correctly reported

  • Every stochastic source is seeded from one generator, and the seed is recorded in the
    result message so it survives sharing and PDF export. Two runs at the same seed produce
    identical trajectories.
  • The MD chart was plotting potential energy under a "total energy" label, which made
    the NVE conservation the docs tell you to verify impossible to see. Potential, kinetic and
    total energy plus temperature are now all recorded and plotted separately. Measured on a
    real run: total drifts 1.4 meV while potential swings 112 meV — the trajectory was
    conserving energy correctly all along.
  • Centre-of-mass drift is removed after velocity initialisation, so reported temperature is
    no longer inflated by rigid translation (mean 201.0 K → 181.3 K on a test run).

A structure-parsing bug that corrupted every crystal

CIF fractional coordinates were never converted through the unit cell. Most
crystallographic CIFs store fractional coordinates, so loading one packed every atom into a
1 Å box — silicon came out with a 0.433 Å nearest-neighbour distance instead of 2.3516 Å, a
factor of 5.4. Every distance, every perceived bond, and any energy computed from it was
meaningless. The parser also read no unit cell at all, so nothing downstream could tell a
crystal from an isolated molecule.

Now fixed for CIF, POSCAR and extended-XYZ, with public/demo/silicon.cif committed as a
regression fixture.

Scientific guardrails at the point of entry

  • MACE-OFF warns when the structure contains elements outside its coverage
    (H, C, N, O, F, P, S, Cl, Br, I).
  • NPT is disabled without a periodic cell, and falls back to NVT if the structure changes.
  • MD timestep ceiling lowered from 10 fs to 4 fs — 10 fs produces garbage and was silently
    allowed.
  • D3 dispersion is locked out where it would double-count, including for custom checkpoints
    whose loader ignores the flag entirely.
  • Every numeric input shows its unit and valid range.

Other fixes

  • D3 dispersion never worked. torch-dftd was in neither our requirements nor
    mace-torch's, so enabling it always failed — after downloading the model. Now installed,
    with a preflight check that fails before any model is fetched if it is missing.
  • Precision follows upstream's defaults (float64 for MACE-OFF and for geometry
    optimisation) instead of being pinned to float32.
  • The docs advertised a FIRE optimiser that does not exist; BFGS is hardcoded.
  • npm run lint was linting a Python virtualenv and reporting 42,891 problems, making the
    project's own "no new warnings" gate meaningless. Now 37, all real.

What SimpleAtom deliberately cannot do

MACE is an interatomic potential. It produces energies, forces and stress, and has no
electron density
— so orbitals, partial charges, Fukui indices, pKa, redox potentials and
NMR shifts are not approximated, stubbed, or hidden behind a "coming soon" toggle. They are
absent, and phonon is rejected with an error rather than quietly running something else.

Verifying it yourself

These must all fail. If any returns a result, a silent fallthrough has come back:

export KMP_DUPLICATE_LIB_OK=TRUE
python3 mace-api/calculate_local.py public/demo/ethanol.xyz '{"calculationType":"phonon"}'
python3 mace-api/calculate_local.py public/demo/ethanol.xyz '{"modelType":"custom"}'
python3 mace-api/calculate_local.py public/demo/ethanol.xyz '{"modelType":"MACE-MP"}'

And the full scientific validation suite:

python3 test_scripts/validate_calculation.py --test

Full documentation: https://mace-lake.vercel.app/docs