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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions