Skip to content

Fix silent float32 precision truncation in MatterSim graph construction #786

Description

@ellalbolland

Summary

GraphConverter.convert (mattersim's own code) hardcodes torch.FloatTensor for atom_pos and cell, always float32, regardless of the calculator's requested dtype. calculate() upcasts afterward, but that is too late: precision already lost to float32 rounding cannot be recovered. This silently violates translational symmetry even at dtype="float64".

Minimal example (periodic structure, so the separate copy() bug in #771 cannot apply):

import numpy as np
from ase.build import graphene
from mattersim.forcefield import MatterSimCalculator

DIRECTION = np.array([37.2, -18.9, 24.6])
DIRECTION = DIRECTION / np.linalg.norm(DIRECTION)
calc = MatterSimCalculator(load_path="mattersim-v1.0.0-5m", device="cpu", dtype="float64")

original = graphene(formula="C2", a=2.46, thickness=0.0, vacuum=10.0)
original.calc = calc
e0, f0 = original.get_potential_energy(), original.get_forces()

translated = original.copy()
translated.translate(DIRECTION * 40.0)
translated.wrap()
translated.calc = calc
e1, f1 = translated.get_potential_energy(), translated.get_forces()

print(abs(e1 - e0) / len(original) * 1000, "meV/atom")
print(np.abs(f1 - f0).max() * 1000, "meV/A")

Output:
0.0 meV/atom
0.007912 meV/A

Expected: both exactly 0. Confirmed cause by rebuilding only atom_pos/cell at float64 instead of float32: delta_F drops to exactly 0.000000.

Platform

macOS 26.5 arm64 (Darwin 25.5.0)

Python version

Python 3.12.13

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions