Skip to content

[Code scan] Symmetrize ASE calculator stress after reshaping virial #5689

Description

@njzjz

This issue comes from a Codex global scan of deepmodeling/deepmd-kit at commit 73de44b1f94471b2e3bdb6b11f57b34d7bc791bb.

Problem

The ASE calculator stores the model virial as a 3x3 matrix:

self.results["energy"] = e[0][0]
# see https://gitlab.com/ase/ase/-/merge_requests/2485
self.results["free_energy"] = e[0][0]
self.results["forces"] = f[0]
self.results["virial"] = v[0].reshape(3, 3)

but when converting virial to stress it operates on the original flat 9-vector v[0]:

# convert virial into stress for lattice relaxation
if cell is not None:
# the usual convention (tensile stress is positive)
# stress = -virial / volume
stress = -0.5 * (v[0].copy() + v[0].copy().T) / atoms.get_volume()
# Voigt notation
self.results["stress"] = stress.flat[[0, 4, 8, 5, 2, 1]]

For a one-dimensional NumPy array, .T is a no-op. Therefore 0.5 * (v[0] + v[0].T) does not symmetrize the virial tensor; it just returns the flat virial vector. The subsequent Voigt indexing then uses unsymmetrized off-diagonal entries.

Impact

ASE stress returned by the DeePMD calculator can be wrong for models/inputs whose virial tensor is not exactly symmetric. This affects workflows that consume ASE stress, including cell/lattice relaxation.

Suggested fix

Reshape before symmetrizing:

virial = v[0].reshape(3, 3)
stress = -0.5 * (virial + virial.T) / atoms.get_volume()
self.results["stress"] = stress.flat[[0, 4, 8, 5, 2, 1]]

Alternatively, reuse self.results["virial"] after assigning it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions