Coverage for cvpack/openmm_force_wrapper.py: 100%
24 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-16 00:10 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-16 00:10 +0000
1"""
2.. class:: OpenMMForceWrapper
3 :platform: Linux, MacOS, Windows
4 :synopsis: A collective variable built from the potential energy of an OpenMM force
6.. classauthor:: Charlles Abreu <craabreu@gmail.com>
8"""
10from __future__ import annotations
12import typing as t
14import openmm
15from openmm import unit as mmunit
17from .collective_variable import CollectiveVariable
18from .units import Unit, VectorQuantity
21class OpenMMForceWrapper(CollectiveVariable, openmm.Force):
22 r"""
23 A collective variable whose numerical value is computed from the potential energy,
24 in kJ/mol, of an OpenMM force object.
26 Parameters
27 ----------
28 openmmForce
29 The OpenMM force whose potential energy will be used to define the collective
30 variable. It can be passed as an instance of :OpenMM:`Force` or as a string
31 containing the XML serialization of the force.
32 unit
33 The unit of measurement of the collective variable. It must be compatible
34 with the MD unit system (mass in `daltons`, distance in `nanometers`, time
35 in `picoseconds`, temperature in `kelvin`, energy in `kilojoules_per_mol`,
36 angle in `radians`). If the collective variable does not have a unit, use
37 `dimensionless`.
38 periodicBounds
39 The periodic bounds of the collective variable if it is periodic, or `None` if
40 it is not.
41 name
42 The name of the collective variable.
44 Example
45 -------
46 >>> import cvpack
47 >>> import numpy as np
48 >>> import openmm
49 >>> from openmm import unit
50 >>> from openmmtools import testsystems
51 >>> model = testsystems.AlanineDipeptideVacuum()
52 >>> torsion = openmm.CustomTorsionForce("theta")
53 >>> _ = torsion.addTorsion(4, 6, 8, 14)
54 >>> cv = cvpack.OpenMMForceWrapper(
55 ... torsion,
56 ... unit.radian,
57 ... periodicBounds=[-np.pi, np.pi] * unit.radian,
58 ... )
59 >>> cv.addToSystem(model.system)
60 >>> integrator = openmm.VerletIntegrator(0)
61 >>> platform = openmm.Platform.getPlatformByName("Reference")
62 >>> context = openmm.Context(model.system, integrator, platform)
63 >>> context.setPositions(model.positions)
64 >>> cv.getValue(context)
65 -3.1415... rad
66 >>> cv.getEffectiveMass(context)
67 0.04795... nm**2 Da/(rad**2)
68 """
70 def __init__(
71 self,
72 openmmForce: openmm.Force | str,
73 unit: mmunit.Unit,
74 periodicBounds: VectorQuantity | None = None,
75 name: str = "openmm_force_wrapper",
76 ) -> None:
77 if isinstance(openmmForce, openmm.Force):
78 openmmForce = openmm.XmlSerializer.serialize(openmmForce)
79 unit = Unit(unit)
80 self._wrapped_force = openmm.XmlSerializer.deserialize(openmmForce)
81 self.this = self._wrapped_force.this
82 self._registerCV(
83 name,
84 unit,
85 openmmForce=openmmForce,
86 unit=unit,
87 periodicBounds=periodicBounds,
88 )
89 if periodicBounds is not None:
90 self._registerPeriodicBounds(*periodicBounds)
92 def __getattr__(self, name: str) -> t.Any:
93 attr = getattr(self._wrapped_force, name)
94 if callable(attr):
96 def _wrapped_method(*args, **kwargs):
97 return attr(*args, **kwargs)
99 return _wrapped_method
101 return attr
104OpenMMForceWrapper.registerTag("!cvpack.OpenMMForceWrapper")