Source code for openff.interchange.operations.minimize.openmm
"""Minimize energy using OpenMM."""
from typing import TYPE_CHECKING
from openff.toolkit import Quantity
from openff.utilities.utilities import requires_package
from openff.interchange.exceptions import MinimizationError, MissingPositionsError
if TYPE_CHECKING:
from openff.interchange import Interchange
[docs]@requires_package("openmm")
def minimize_openmm(
interchange: "Interchange",
tolerance: Quantity,
max_iterations: int,
) -> Quantity:
"""Minimize the energy of a system using OpenMM."""
import openmm
import openmm.unit
from openff.units.openmm import from_openmm
simulation = interchange.to_openmm_simulation(
integrator=openmm.LangevinMiddleIntegrator(
293.15 * openmm.unit.kelvin,
1.0 / openmm.unit.picosecond,
2.0 * openmm.unit.femtosecond,
),
combine_nonbonded_forces=False,
)
simulation.context.computeVirtualSites()
try:
simulation.minimizeEnergy(
tolerance=tolerance.to_openmm(),
maxIterations=max_iterations,
)
except openmm.OpenMMException as error:
if "Particle positions have not been set" in str(error):
raise MissingPositionsError(
f"Cannot minimize without positions. Found {interchange.positions=}.",
) from error
else:
raise MinimizationError("OpenMM Minimization failed.") from error
# Assume that all virtual sites are placed at the _end_, so the 0th through
# (number of atoms)th positions are the massive particles
return from_openmm(
simulation.context.getState(getPositions=True).getPositions(asNumpy=True)[
: interchange.positions.shape[0],
:,
],
)