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
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