|
|
|
|
|
import numpy as np |
|
|
import openmm.unit as unit |
|
|
from abc import abstractmethod, ABC |
|
|
from scipy.constants import physical_constants |
|
|
|
|
|
|
|
|
class BaseDynamics(ABC): |
|
|
def __init__(self, args, state): |
|
|
super().__init__() |
|
|
self.start_file = f"./data/{args.molecule}/{state}.pdb" |
|
|
self.temperature = args.temperature * unit.kelvin |
|
|
self.friction = args.friction / unit.femtoseconds |
|
|
self.timestep = args.timestep * unit.femtoseconds |
|
|
self.pdb, self.integrator, self.simulation, self.external_force = self.setup() |
|
|
self.get_md_info() |
|
|
self.simulation.minimizeEnergy() |
|
|
self.position = self.report()[0] |
|
|
|
|
|
@abstractmethod |
|
|
def setup(self): |
|
|
pass |
|
|
|
|
|
def get_md_info(self): |
|
|
self.num_particles = self.simulation.system.getNumParticles() |
|
|
m = np.array([ |
|
|
self.simulation.system.getParticleMass(i).value_in_unit(unit.dalton) |
|
|
for i in range(self.num_particles) |
|
|
]) |
|
|
self.heavy_atoms = m > 1.1 |
|
|
m = unit.Quantity(m, unit.dalton) |
|
|
unadjusted_variance = ( |
|
|
2 * self.timestep * self.friction * unit.BOLTZMANN_CONSTANT_kB * self.temperature / m[:, None] |
|
|
) |
|
|
std_SI_units = ( |
|
|
1 / physical_constants["unified atomic mass unit"][0] * |
|
|
unadjusted_variance.value_in_unit(unit.joule / unit.dalton) |
|
|
) |
|
|
self.std = unit.Quantity( |
|
|
np.sqrt(std_SI_units), unit.meter / unit.second |
|
|
).value_in_unit(unit.nanometer / unit.femtosecond) |
|
|
self.m = m.value_in_unit(unit.dalton) |
|
|
|
|
|
def step(self, forces): |
|
|
for i in range(forces.shape[0]): |
|
|
self.external_force.setParticleParameters(i, i, forces[i]) |
|
|
self.external_force.updateParametersInContext(self.simulation.context) |
|
|
self.simulation.step(1) |
|
|
|
|
|
def report(self): |
|
|
state = self.simulation.context.getState(getPositions=True, getForces=True) |
|
|
positions = state.getPositions().value_in_unit(unit.nanometer) |
|
|
forces = state.getForces().value_in_unit( |
|
|
unit.dalton * unit.nanometer / unit.femtosecond ** 2 |
|
|
) |
|
|
return positions, forces |
|
|
|
|
|
def reset(self): |
|
|
for i in range(len(self.position)): |
|
|
self.external_force.setParticleParameters(i, i, [0, 0, 0]) |
|
|
self.external_force.updateParametersInContext(self.simulation.context) |
|
|
self.simulation.context.setPositions(self.position) |
|
|
self.simulation.context.setVelocitiesToTemperature(self.temperature) |
|
|
|
|
|
def set_temperature(self, temperature): |
|
|
self.integrator.setTemperature(temperature * unit.kelvin) |
|
|
|
|
|
def energy_function(self, positions): |
|
|
forces, potentials = [], [] |
|
|
for i in range(len(positions)): |
|
|
self.simulation.context.setPositions(positions[i]) |
|
|
state = self.simulation.context.getState(getForces=True, getEnergy=True) |
|
|
force = state.getForces().value_in_unit( |
|
|
unit.dalton * unit.nanometer / unit.femtosecond ** 2 |
|
|
) |
|
|
potential = state.getPotentialEnergy().value_in_unit( |
|
|
unit.kilojoules / unit.mole |
|
|
) |
|
|
forces.append(force) |
|
|
potentials.append(potential) |
|
|
return np.array(forces), np.array(potentials) |
|
|
|