Source code for openxps.bounds.reflective
"""
Reflective boundary condition.
.. module:: openxps.bounds.reflective
:platform: Linux, MacOS, Windows
:synopsis: Reflective boundary condition
.. classauthor:: Charlles Abreu <craabreu@gmail.com>
"""
import typing as t
from .base import Bounds
[docs]
class ReflectiveBounds(Bounds):
"""
A reflective boundary condition. The dynamical variable collides elastically
with the upper and lower bounds and is reflected back into the range.
Parameters
----------
lower
The lower bound for the dynamical variable.
upper
The upper bound for the dynamical variable.
unit
The unit of measurement of the bounds. If the bounds do not have a unit, use
``dimensionless``.
Example
-------
>>> import openxps as xps
>>> from openmm import unit
>>> bounds = xps.ReflectiveBounds(1, 10, unit.angstrom)
>>> bounds == xps.ReflectiveBounds(0.1, 1, unit.nanometer)
True
>>> print(bounds)
ReflectiveBounds(lower=1.0, upper=10.0, unit=A)
"""
kind: t.ClassVar[str] = "reflective"
def __post_init__(self) -> None:
super().__post_init__()
self.period = 2 * (self.upper - self.lower)
[docs]
def leptonExpression(self, variable: str) -> str:
scaled = f"scaled_{variable}"
wrapped = f"wrapped_{variable}"
if self.lower == 0:
shift = deshift = ""
elif self.lower > 0:
shift = f"-{self.lower}"
deshift = f"+{self.lower}"
else:
shift = f"+{-self.lower}"
deshift = f"-{-self.lower}"
return (
f"min({wrapped},1-{wrapped})*{self.period}{deshift}"
f";\n{wrapped}={scaled}-floor({scaled})"
f";\n{scaled}=({variable}{shift})/{self.period}"
)
[docs]
def wrap(self, value: float, rate: float) -> tuple[float, float]:
x = (value - self.lower) % self.period
if x < self.period - x:
return x + self.lower, rate
return self.period - x + self.lower, -rate
ReflectiveBounds.registerTag("!openxps.bounds.ReflectiveBounds")