Overwriting ASE Calculator Results and Saving Results to a Trajectory File


I’m using ASE to do Monte Carlo (MC) simulations, and I am using the ASE trajectory file format to save the trajectory, energies, forces, etc… When moves are accepted, the atomic coordinates and calculation results saves to the trajectory file as expected. However, when a move gets rejected, I restore the old coordinates of the atoms and I try to restore the calculator results with the original calculator results before the MC trial move. Unfortunately, the calculator results are not being written to the trajectory file, and only the atomic coordinates and cell information are being written. So far, the only solution I have found is to make another potential energy call if a move is rejected. If possible, I would like to avoid doing this since we already have forces and energies in this old configuration. Below is some pseudocode for what I have currently tried.

position_o = atoms.get_positions()
results_o = atoms.calc.results

# Do a MC move
# If accepted, great!

if rejected:
    atoms.calc.results = results_o # Does not write to trajectory file
    energy = atoms.get_potential_energy() # Writes to trajectory file, but launches another calculation

While there is a workaround I can use to get the calculator results for a previous configuration in the analysis scripts I have, it would be nice if the old calculator results are written directly to the trajectory file. Is there an attribute I can set or a method I can call either in the Atoms or Calculator objects to do this? Any help would be much appreciated. Thanks!

I’m not sure what code you are using to write to the trajectory in the first place, so it is not clear whether we expect them to include properties.

I suggest separating the trajectory-writing Atoms from the calculation Atoms, so they are not touched by the recalculation. Something like:

def copy_with_properties(atoms: Atoms) -> Atoms:
    atoms_copy = atoms.copy()
    atoms_copy.calc = SinglePointCalculator(
    return atoms_copy

def save_to_traj(atoms: Atoms, filename: str = 'mc.traj') -> None:
    with Trajectory(filename, mode='a') as traj:

last_good_step = None
for _ in range(mc_steps):
    if _accept(atoms):  # _accept() should run atoms.get_forces() and return bool
        last_good_step = copy_with_properties(atoms)
    if last_good_step is not None:
    _mc_mutate(atoms)  # Mutate atoms in place without touching calculator

Hi Adam, thank you for the suggestion I’ll try this out!