Ase.io.write() now frequently throws errors that it never did before

I have been using ASE for years now without many issues at all. After updating to the most recent version, many of the things that I did before now throw errors, and I am not sure why (or if there is a way to fix it). Any guidance would be greatly appreciated!

I am simply trying to convert an ‘md.traj’ file to the ‘extxyz’ format so I can visualize it in Ovito. The script is obviously very simple:

from ase.io import read, write
traj = read('md.traj',index=':')
write('md.xyz',traj,format='extxyz')

This code works perfectly on version 3.22.1, but throws the following error on version 3.23.0:

Traceback (most recent call last):
  File "~/convert.py", line 6, in <module>
    write('md.xyz',traj,format='extxyz')
  File "~/miniconda3/envs/pyquip/lib/python3.10/site-packages/ase/io/formats.py", line 692, in write
    return _write(filename, fd, format, io, images,
  File "~/miniconda3/envs/pyquip/lib/python3.10/site-packages/ase/parallel.py", line 271, in new_func
    return func(*args, **kwargs)
  File "~/miniconda3/envs/pyquip/lib/python3.10/site-packages/ase/io/formats.py", line 728, in _write
    return io.write(fd, images, **kwargs)
  File "~/miniconda3/envs/pyquip/lib/python3.10/site-packages/ase/io/formats.py", line 193, in _write_wrapper
    return function(*args, **kwargs)
  File "~/miniconda3/envs/pyquip/lib/python3.10/site-packages/ase/utils/__init__.py", line 577, in iofunc
    obj = func(fd, *args, **kwargs)
  File "~/miniconda3/envs/pyquip/lib/python3.10/site-packages/ase/io/extxyz.py", line 826, in write_xyz
    save_calc_results(atoms, calculator, calc_prefix="")
  File "~/miniconda3/envs/pyquip/lib/python3.10/site-packages/ase/io/extxyz.py", line 987, in save_calc_results
    raise KeyError("key from calculator already exists in atoms.info")
KeyError: 'key from calculator already exists in atoms.info'

Thank you in advance for your help!

I just did a quick test with EMT and a Langevin thermostat, and the .traj file from this typical ASE MD run seems to load and write to .extxyz without issue. So this does not affect all .traj files; it is something to do with the way yours was constructed.

This error message arises when a property has been stored with the same name in both the Calculator data and elsewhere in the Atoms object (e.g. a field “forces” in both the Calculator results and in atoms.arrays, or a field “potential_energy” in both the Calculator results and atoms.info.) When serialising such data with extxyz the situation is ambiguous: which set of data should take priority? In the previous version of ASE one of these would take priority, but this was seen as a buggy/ill-defined behaviour and has been (slightly controversially) fixed by raising an error in the current release.

Presumably your .traj was created by some Python code that copied forces, energy etc. to atoms.arrays and atoms.info while leaving a Calculator attached. If you are confident that this is the correct data you want to use, then you should be able to clean up the situation with something like

from ase.io import read, write
traj = read('md.traj',index=':')
for atoms in traj:
    atoms.calc = None
write('md.xyz', traj, format='extxyz')

A function has been added here to assist with moving data from Calculators to info/arrays, using a prefix to distinguish between calculations:

This should be especially helpful for machine-learning workflows where one might like to write “D3_energy”, “PBE_energy” and “gen8_MLIP_energy” from different calculators as separate fields in the same XYZ file.

1 Like

Thank you so much for looking into this! That makes total sense. Yes you are correct that I updated the forces in the traj externally on top of having a calculator attached to it.

In this case, I do want to read the forces that I set, not the ones from the calculator, so it seems your fix is achieving my goal.

Thanks again!

Best,
Sam

1 Like