Thanks to visit codestin.com
Credit goes to gist.github.com

Skip to content

Instantly share code, notes, and snippets.

@lukasmki
Created November 20, 2024 19:22
Show Gist options
  • Select an option

  • Save lukasmki/3e5322dd221f71e6ce1abdb52b484c2c to your computer and use it in GitHub Desktop.

Select an option

Save lukasmki/3e5322dd221f71e6ce1abdb52b484c2c to your computer and use it in GitHub Desktop.
Nanoreactor + Langevin Integrator for the Atomic Simulation Environment (ASE)
""" Nanoreactor + Langevin Integrator
Wang, LP., Titov, A., McGibbon, R. et al. Discovering chemistry with an ab initio nanoreactor. Nature Chem 6, 1044-1048 (2014). https://doi.org/10.1038/nchem.2099
"""
import numpy as np
from ase import Atoms, units
from ase.md.langevin import Langevin
class Nanoreactor(Langevin):
def __init__(
self,
atoms,
timestep,
k1=1.0,
k2=0.5,
r1=14,
r2=8.0,
tau_ps=1.5,
T_ps=2.0,
**kwargs,
):
Langevin.__init__(self, atoms, timestep, **kwargs)
self.k1 = k1 * units.kcal / units.mol / units.Angstrom**2
self.k2 = k2 * units.kcal / units.mol / units.Angstrom**2
self.r1 = r1 * units.Angstrom
self.r2 = r2 * units.Angstrom
self.period = T_ps * 1000.0 * units.fs
self.tau = tau_ps * 1000.0 * units.fs
def boundary(self) -> tuple[np.ndarray, np.ndarray]:
box_center = self.atoms.get_cell() @ np.array([0.5, 0.5, 0.5])
V = self.atoms.positions - box_center
D = np.sqrt(np.sum(V * V, -1))
Vhat = V / (D[:, None] + 1e-8)
# Boundary potential
t = self.get_time()
ft = np.heaviside(
np.floor(t / self.period) - (t / self.period) + (self.tau / self.period), 1
)
U1 = 0.5 * self.k1 * np.square(D - self.r1) * np.heaviside(D - self.r1, 1)
U2 = 0.5 * self.k2 * np.square(D - self.r2) * np.heaviside(D - self.r2, 1)
U = ft * U1 + (1 - ft) * U2
# Force
F1 = (
-Vhat
* self.k1
* (D - self.r1)[:, None]
* np.heaviside(D - self.r1, 1)[:, None]
)
F2 = (
-Vhat
* self.k2
* (D - self.r2)[:, None]
* np.heaviside(D - self.r2, 1)[:, None]
)
F = ft * F1 + (1 - ft) * F2
return U, F
def step(self, forces=None):
atoms: Atoms = self.atoms
if forces is None:
forces = atoms.get_forces()
# Nanoreactor boundary potential
U, F = self.boundary()
forces += F
# MD step
Langevin.step(self, forces)
return forces
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment