Coverage for cvpack/angle.py: 100%
10 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:: Angle
3 :platform: Linux, MacOS, Windows
4 :synopsis: The angle formed by three atoms
6.. classauthor:: Charlles Abreu <craabreu@gmail.com>
8"""
10import openmm
11from openmm import unit as mmunit
13from .collective_variable import CollectiveVariable
16class Angle(CollectiveVariable, openmm.CustomAngleForce):
17 r"""
18 The angle formed by three atoms:
20 .. math::
22 \theta({\bf r}) =
23 \mathrm{acos}\left(
24 \frac{{\bf r}_{2,1} \cdot {\bf r}_{2,3} }
25 {\| {\bf r}_{2,1} \| \| {\bf r}_{2,3} \|}
26 \right),
28 where :math:`{\bf r}_{i,j} = {\bf r}_j - {\bf r}_i`.
30 Parameters
31 ----------
32 atom1
33 The index of the first atom.
34 atom2
35 The index of the second atom.
36 atom3
37 The index of the third atom.
38 pbc
39 Whether to use periodic boundary conditions.
40 name
41 The name of the collective variable.
43 Example
44 -------
45 >>> import cvpack
46 >>> import openmm
47 >>> system = openmm.System()
48 >>> [system.addParticle(1) for i in range(3)]
49 [0, 1, 2]
50 >>> angle = cvpack.Angle(0, 1, 2)
51 >>> system.addForce(angle)
52 0
53 >>> integrator = openmm.VerletIntegrator(0)
54 >>> platform = openmm.Platform.getPlatformByName('Reference')
55 >>> context = openmm.Context(system, integrator, platform)
56 >>> positions = [[0, 0, 0], [1, 0, 0], [1, 1, 0]]
57 >>> context.setPositions([openmm.Vec3(*pos) for pos in positions])
58 >>> angle.getValue(context)
59 1.570796... rad
61 """
63 def __init__(
64 self,
65 atom1: int,
66 atom2: int,
67 atom3: int,
68 pbc: bool = False,
69 name: str = "angle",
70 ) -> None:
71 super().__init__("theta")
72 self.addAngle(atom1, atom2, atom3, [])
73 self.setUsesPeriodicBoundaryConditions(pbc)
74 self._registerCV(
75 name, mmunit.radians, atom1=atom1, atom2=atom2, atom3=atom3, pbc=pbc
76 )
79Angle.registerTag("!cvpack.Angle")