forked from noegroup/torchmd-autodiff
-
Notifications
You must be signed in to change notification settings - Fork 5
/
integrator.py
78 lines (58 loc) · 2.14 KB
/
integrator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import numpy as np
import torch
TIMEFACTOR = 48.88821
BOLTZMAN = 0.001987191
def kinetic_energy(masses, vel):
Ekin = torch.sum(0.5 * torch.sum(vel * vel, dim=2, keepdim=True) * masses, dim=1)
return Ekin
def maxwell_boltzmann(masses, T, replicas=1):
natoms = len(masses)
velocities = []
for i in range(replicas):
velocities.append(
torch.sqrt(T * BOLTZMAN / masses) * torch.randn((natoms, 3)).type_as(masses)
)
return torch.stack(velocities, dim=0)
def kinetic_to_temp(Ekin, natoms):
return 2.0 / (3.0 * natoms * BOLTZMAN) * Ekin
def _first_VV(pos, vel, force, mass, dt):
accel = force / mass
newpos = pos + vel * dt + 0.5 * accel * dt * dt
newvel = vel + 0.5 * dt * accel
return newpos, newvel
def _second_VV(vel, force, mass, dt):
accel = force / mass
newvel = vel + 0.5 * dt * accel
return newvel
def langevin(vel, gamma, coeff, dt, device):
csi = torch.randn_like(vel, device=device) * coeff
newvel = vel - gamma * vel * dt + csi
return newvel
PICOSEC2TIMEU = 1000.0 / TIMEFACTOR
class Integrator:
def __init__(self, systems, forces, timestep, device, gamma=None, T=None):
self.dt = timestep / TIMEFACTOR
self.systems = systems
self.forces = forces
self.device = device
gamma = gamma / PICOSEC2TIMEU
self.gamma = gamma
self.T = T
if T:
M = self.forces.par.masses
self.vcoeff = torch.sqrt(2.0 * gamma / M * BOLTZMAN * T * self.dt).to(
device
)
def step(self, niter=1):
s = self.systems
masses = self.forces.par.masses
natoms = len(masses)
for _ in range(niter):
s.pos, s.vel = _first_VV(s.pos, s.vel, s.forces, masses, self.dt)
pot = self.forces.compute(s.pos, s.box, s.forces)
if self.T:
s.vel = langevin(s.vel, self.gamma, self.vcoeff, self.dt, self.device)
s.vel = _second_VV(s.vel, s.forces, masses, self.dt)
Ekin = np.array([v.item() for v in kinetic_energy(masses, s.vel)])
T = kinetic_to_temp(Ekin, natoms)
return Ekin, pot, T