Summary
atompack.from_ase currently appears to store ASE custom arrays as molecule-scope custom properties. This causes schema mismatches when writing multiple structures with different atom counts into one .atp file.
ASE arrays such as atoms.arrays["tags"] or atoms.arrays["fixed_mask"] have per-atom semantics: their first dimension is n_atoms. I would expect these to become AtomPack atom-scoped properties, or for from_ase to expose a way to preserve or specify that scope.
Instead, they are stored as molecule-scope properties with a fixed slot size. When the next molecule has a different atom count, writing fails.
Minimal Repro
from pathlib import Path
import tempfile
import atompack
import numpy as np
from ase import Atoms
path = Path(tempfile.mkdtemp()) / "variable_atom_array.atp"
def make(n):
atoms = Atoms(
numbers=[1] * n,
positions=np.zeros((n, 3)),
cell=np.eye(3),
pbc=True,
)
atoms.arrays["fixed_mask"] = np.zeros(n, dtype=np.int64)
return atompack.from_ase(atoms)
db = atompack.Database(str(path))
db.add_molecules([make(3), make(4)])
db.flush()
Actual Behavior
This fails with a schema mismatch similar to:
ValueError: Invalid data: Schema mismatch for section fixed_mask:
expected SchemaEntry { ..., per_atom: false, elem_bytes: 8, slot_bytes: 24 },
got SchemaEntry { ..., per_atom: false, elem_bytes: 8, slot_bytes: 32 }
The important bit is per_atom: false.
Expected Behavior
Since fixed_mask comes from atoms.arrays and has shape (n_atoms,), it should either:
- be stored as an atom-scoped property,
- provide a
from_ase argument to declare custom array scope, or
- document clearly that
from_ase(copy_arrays=True) stores all custom arrays as molecule-scope properties.
Workaround
This works:
from pathlib import Path
import tempfile
import atompack
import numpy as np
from ase import Atoms
path = Path(tempfile.mkdtemp()) / "variable_atom_array_workaround.atp"
def make(n):
atoms = Atoms(
numbers=[1] * n,
positions=np.zeros((n, 3)),
cell=np.eye(3),
pbc=True,
)
mol = atompack.from_ase(
atoms,
copy_arrays=False,
copy_info=False,
)
mol.set_property(
"fixed_mask",
np.zeros(n, dtype=np.int32),
scope="atom",
)
return mol
db = atompack.Database(str(path))
db.add_molecules([make(3), make(4)])
db.flush()
Note: scope="atom" works, but the dtype must be one of the supported numeric dtypes. bool and int8 fail; int32, int64, float32, and float64 work.
Environment
Observed with atompack-db==0.4.0.
Summary
atompack.from_asecurrently appears to store ASE custom arrays as molecule-scope custom properties. This causes schema mismatches when writing multiple structures with different atom counts into one.atpfile.ASE arrays such as
atoms.arrays["tags"]oratoms.arrays["fixed_mask"]have per-atom semantics: their first dimension isn_atoms. I would expect these to become AtomPack atom-scoped properties, or forfrom_aseto expose a way to preserve or specify that scope.Instead, they are stored as molecule-scope properties with a fixed slot size. When the next molecule has a different atom count, writing fails.
Minimal Repro
Actual Behavior
This fails with a schema mismatch similar to:
The important bit is
per_atom: false.Expected Behavior
Since
fixed_maskcomes fromatoms.arraysand has shape(n_atoms,), it should either:from_aseargument to declare custom array scope, orfrom_ase(copy_arrays=True)stores all custom arrays as molecule-scope properties.Workaround
This works:
Note:
scope="atom"works, but the dtype must be one of the supported numeric dtypes.boolandint8fail;int32,int64,float32, andfloat64work.Environment
Observed with
atompack-db==0.4.0.