Coverage for cvpack/torsion.py: 100%

12 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-09 16:14 +0000

1""" 

2.. class:: Torsion 

3 :platform: Linux, MacOS, Windows 

4 :synopsis: The torsion angle formed by four atoms 

5 

6.. classauthor:: Charlles Abreu <craabreu@gmail.com> 

7 

8""" 

9 

10import numpy as np 

11import openmm 

12from openmm import unit as mmunit 

13 

14from .collective_variable import CollectiveVariable 

15 

16 

17class Torsion(CollectiveVariable, openmm.CustomTorsionForce): 

18 r""" 

19 The torsion angle formed by four atoms: 

20 

21 .. math:: 

22 

23 \varphi({\bf r}) = {\rm atan2}\left(\frac{ 

24 ({\bf r}_{2,1} \times {\bf r}_{3,4}) \cdot {\bf u}_{2,3} 

25 }{ 

26 {\bf r}_{2,1} \cdot {\bf r}_{3,4} - 

27 ({\bf r}_{2,1} \cdot {\bf u}_{2,3}) 

28 ({\bf r}_{3,4} \cdot {\bf u}_{2,3}) 

29 }\right), 

30 

31 where :math:`{\bf r}_{i,j} = {\bf r}_j - {\bf r}_i`, 

32 :math:`{\bf u}_{2,3} = {\bf r}_{2,3}/\|{\bf r}_{2,3}\|`, 

33 and `atan2 <https://en.wikipedia.org/wiki/Atan2>`_ is the arctangent function that 

34 receives the numerator and denominator above as separate arguments. 

35 

36 Parameters 

37 ---------- 

38 atom1 

39 The index of the first atom. 

40 atom2 

41 The index of the second atom. 

42 atom3 

43 The index of the third atom. 

44 atom4 

45 The index of the fourth atom. 

46 pbc 

47 Whether to use periodic boundary conditions in distance calculations. 

48 name 

49 The name of the collective variable. 

50 

51 Example 

52 ------- 

53 >>> import cvpack 

54 >>> import openmm 

55 >>> system = openmm.System() 

56 >>> [system.addParticle(1) for i in range(4)] 

57 [0, 1, 2, 3] 

58 >>> torsion = cvpack.Torsion(0, 1, 2, 3, pbc=False) 

59 >>> system.addForce(torsion) 

60 0 

61 >>> integrator = openmm.VerletIntegrator(0) 

62 >>> platform = openmm.Platform.getPlatformByName('Reference') 

63 >>> context = openmm.Context(system, integrator, platform) 

64 >>> positions = [[0, 0, 0], [1, 0, 0], [1, 1, 0], [1, 1, 1]] 

65 >>> context.setPositions([openmm.Vec3(*pos) for pos in positions]) 

66 >>> torsion.getValue(context) 

67 1.5707... rad 

68 

69 """ 

70 

71 def __init__( 

72 self, 

73 atom1: int, 

74 atom2: int, 

75 atom3: int, 

76 atom4: int, 

77 pbc: bool = False, 

78 name: str = "torsion", 

79 ) -> None: 

80 super().__init__("theta") 

81 self.addTorsion(atom1, atom2, atom3, atom4, []) 

82 self.setUsesPeriodicBoundaryConditions(pbc) 

83 self._registerCV( 

84 name, 

85 mmunit.radians, 

86 atom1=atom1, 

87 atom2=atom2, 

88 atom3=atom3, 

89 atom4=atom4, 

90 pbc=pbc, 

91 ) 

92 self._registerPeriodicBounds(-np.pi, np.pi) 

93 

94 

95Torsion.registerTag("!cvpack.Torsion")