Coverage for openxps/integrators/symmetric_langevin.py: 95%
42 statements
« prev ^ index » next coverage.py v7.11.3, created at 2025-11-13 22:08 +0000
« prev ^ index » next coverage.py v7.11.3, created at 2025-11-13 22:08 +0000
1"""
2.. module:: openxps.integrators.symmetric_langevin
3 :platform: Linux, MacOS, Windows
4 :synopsis: BAOAB integrator.
6.. classauthor:: Charlles Abreu <craabreu@gmail.com>
8"""
10import numpy as np
11import openmm as mm
12from openmm import unit as mmunit
14from openxps.utils import preprocess_args
16from .utils import IntegratorMixin, add_property
19@add_property("temperature", mmunit.kelvin)
20@add_property("friction coefficient", 1 / mmunit.picosecond)
21class SymmetricLangevinIntegrator(IntegratorMixin, mm.CustomIntegrator):
22 """A symmetric Langevin integrator using the BAOAB algorithm :cite:`Leimkuhler2013`.
24 Parameters
25 ----------
26 temperature
27 The temperature of the heat bath.
28 frictionCoeff
29 The friction coefficient which couples the system to the heat bath.
30 stepSize
31 The step size with which to integrate the system.
33 Example
34 -------
35 >>> import openxps as xps
36 >>> from openmm import unit
37 >>> integrator = xps.integrators.SymmetricLangevinIntegrator(
38 ... 300 * unit.kelvin, 1 / unit.picosecond, 1 * unit.femtosecond
39 ... )
40 >>> integrator
41 Per-dof variables:
42 x1
43 Global variables:
44 kT = 2.49433...
45 a = 0.999000...
46 b = 0.044699...
47 Computation steps:
48 0: allow forces to update the context state
49 1: v <- v + 0.5*dt*f/m
50 2: constrain velocities
51 3: x <- x + 0.5*dt*v
52 4: v <- a*v + b*sqrt(kT/m)*gaussian
53 5: x <- x + 0.5*dt*v
54 6: x1 <- x
55 7: constrain positions
56 8: v <- v + (x-x1)/dt + 0.5*dt*f/m
57 9: constrain velocities
58 """
60 @preprocess_args
61 def __init__(
62 self,
63 temperature: mmunit.Quantity,
64 frictionCoeff: mmunit.Quantity,
65 stepSize: mmunit.Quantity,
66 ) -> None:
67 super().__init__(stepSize)
68 self._init_temperature(temperature)
69 self._init_friction_coefficient(frictionCoeff)
70 self._add_variables()
71 self.addUpdateContextState()
72 self.addComputePerDof("v", "v + 0.5*dt*f/m")
73 self.addConstrainVelocities()
74 self.addComputePerDof("x", "x + 0.5*dt*v")
75 self.addComputePerDof("v", "a*v + b*sqrt(kT/m)*gaussian")
76 self.addComputePerDof("x", "x + 0.5*dt*v")
77 self.addComputePerDof("x1", "x")
78 self.addConstrainPositions()
79 self.addComputePerDof("v", "v + (x-x1)/dt + 0.5*dt*f/m")
80 self.addConstrainVelocities()
82 def _add_variables(self) -> None:
83 self.addGlobalVariable("kT", 0)
84 self.addGlobalVariable("a", 0)
85 self.addGlobalVariable("b", 0)
86 self.addPerDofVariable("x1", 0)
87 self._update_global_variables()
89 def _update_global_variables(self) -> None:
90 kt = mmunit.MOLAR_GAS_CONSTANT_R * self.getTemperature()
91 friction = self.getFrictionCoefficient()
92 dt = self.getStepSize()
93 a = np.exp(-friction * dt)
94 b = np.sqrt(1 - a**2)
95 self.setGlobalVariableByName("kT", kt)
96 self.setGlobalVariableByName("a", a)
97 self.setGlobalVariableByName("b", b)
99 def setStepSize(self, size: mmunit.Quantity) -> None:
100 super().setStepSize(size)
101 self._update_global_variables()