Commit be9c2e25 authored by Charlles Abreu's avatar Charlles Abreu
Browse files

Metadynamics: grid expansion for periodic variables in 2D/3D cases

parent 8097a594
...@@ -271,7 +271,7 @@ class WellTemperedMetadynamics(Metadynamics): ...@@ -271,7 +271,7 @@ class WellTemperedMetadynamics(Metadynamics):
""" """
def __init__(self, system, variables, temperature, biasFactor, height, frequency, saveFrequency=None, biasDir=None): def __init__(self, system, variables, temperature, biasFactor, height, frequency, saveFrequency=None, biasDir=None, gridExpansion=20):
"""Create a Metadynamics object. """Create a Metadynamics object.
Parameters Parameters
...@@ -299,6 +299,9 @@ class WellTemperedMetadynamics(Metadynamics): ...@@ -299,6 +299,9 @@ class WellTemperedMetadynamics(Metadynamics):
biasDir: str (optional) biasDir: str (optional)
the directory to which biases should be written, and from which biases written by the directory to which biases should be written, and from which biases written by
other processes should be loaded other processes should be loaded
gridExpansion: int (optional)
the extra number of grid points used in periodic directions for multidimensional
tabulated functions
""" """
if not unit.is_quantity(temperature): if not unit.is_quantity(temperature):
temperature = temperature*unit.kelvin temperature = temperature*unit.kelvin
...@@ -319,17 +322,25 @@ class WellTemperedMetadynamics(Metadynamics): ...@@ -319,17 +322,25 @@ class WellTemperedMetadynamics(Metadynamics):
self.saveFrequency = saveFrequency self.saveFrequency = saveFrequency
self._id = np.random.randint(0x7FFFFFFF) self._id = np.random.randint(0x7FFFFFFF)
self._saveIndex = 0 self._saveIndex = 0
self._selfBias = np.zeros(tuple(v.gridWidth for v in reversed(variables))) for v in variables:
self._totalBias = np.zeros(tuple(v.gridWidth for v in reversed(variables))) v._expanded = v.periodic and len(variables) > 1
v._extraWidth = min(gridExpansion, v.gridWidth) if v._expanded else 0
extraRange = v._extraWidth*(v.maxValue - v.minValue)/(v.gridWidth - 1)
v._actualWidth = v.gridWidth + 2*v._extraWidth
v._actualMin = v.minValue - extraRange
v._actualMax = v.maxValue + extraRange
v._slice = slice(v._extraWidth, v.gridWidth + v._extraWidth)
self._selfBias = np.zeros(tuple(v._actualWidth for v in reversed(variables)))
self._totalBias = np.zeros(tuple(v._actualWidth for v in reversed(variables)))
self._loadedBiases = {} self._loadedBiases = {}
self._deltaT = temperature*(biasFactor-1) self._deltaT = temperature*(biasFactor-1)
varNames = ['cv%d' % i for i in range(len(variables))] varNames = ['cv%d' % i for i in range(len(variables))]
self._force = mm.CustomCVForce('table(%s)' % ', '.join(varNames)) self._force = mm.CustomCVForce('table(%s)' % ', '.join(varNames))
for name, var in zip(varNames, variables): for name, var in zip(varNames, variables):
self._force.addCollectiveVariable(name, var.force) self._force.addCollectiveVariable(name, var.force)
widths = [v.gridWidth for v in variables] widths = [v._actualWidth for v in variables]
mins = [v.minValue for v in variables] mins = [v._actualMin for v in variables]
maxs = [v.maxValue for v in variables] maxs = [v._actualMax for v in variables]
if len(variables) == 1: if len(variables) == 1:
self._table = mm.Continuous1DFunction(self._totalBias.flatten(), mins[0], maxs[0], variables[0].periodic) self._table = mm.Continuous1DFunction(self._totalBias.flatten(), mins[0], maxs[0], variables[0].periodic)
elif len(variables) == 2: elif len(variables) == 2:
...@@ -343,6 +354,23 @@ class WellTemperedMetadynamics(Metadynamics): ...@@ -343,6 +354,23 @@ class WellTemperedMetadynamics(Metadynamics):
system.addForce(self._force) system.addForce(self._force)
self._syncWithDisk() self._syncWithDisk()
def getFreeEnergy(self):
"""Get the free energy of the system as a function of the collective variables.
The result is returned as a N-dimensional NumPy array, where N is the number of collective
variables. The values are in kJ/mole. The i'th position along an axis corresponds to
minValue + i*(maxValue-minValue)/gridWidth.
"""
f = -((self.temperature+self._deltaT)/self._deltaT)*self._totalBias*unit.kilojoules_per_mole
if len(self.variables) == 1:
return f
else:
s = [v._slice for v in self.variables]
if len(self.variables) == 2:
return f[s[1], s[0]]
else:
return f[s[2], s[1], s[0]]
def _addGaussian(self, position, height, context): def _addGaussian(self, position, height, context):
"""Add a Gaussian to the bias function.""" """Add a Gaussian to the bias function."""
# Compute a Gaussian along each axis. # Compute a Gaussian along each axis.
...@@ -355,7 +383,11 @@ class WellTemperedMetadynamics(Metadynamics): ...@@ -355,7 +383,11 @@ class WellTemperedMetadynamics(Metadynamics):
dist = np.abs(np.linspace(0, 1.0, num=v.gridWidth) - x) dist = np.abs(np.linspace(0, 1.0, num=v.gridWidth) - x)
if v.periodic: if v.periodic:
dist = np.min(np.array([dist, np.abs(dist-1)]), axis=0) dist = np.min(np.array([dist, np.abs(dist-1)]), axis=0)
axisGaussians.append(np.exp(-0.5*dist*dist/v._scaledVariance)) values = np.exp(-0.5*dist*dist/v._scaledVariance)
if v._expanded:
n = v._extraWidth + 1
values = np.hstack((values[-n:-1], values, values[1:n]))
axisGaussians.append(values)
# Compute their outer product. # Compute their outer product.
...@@ -369,9 +401,9 @@ class WellTemperedMetadynamics(Metadynamics): ...@@ -369,9 +401,9 @@ class WellTemperedMetadynamics(Metadynamics):
height = height.value_in_unit(unit.kilojoules_per_mole) height = height.value_in_unit(unit.kilojoules_per_mole)
self._selfBias += height*gaussian self._selfBias += height*gaussian
self._totalBias += height*gaussian self._totalBias += height*gaussian
widths = [v.gridWidth for v in self.variables] widths = [v._actualWidth for v in self.variables]
mins = [v.minValue for v in self.variables] mins = [v._actualMin for v in self.variables]
maxs = [v.maxValue for v in self.variables] maxs = [v._actualMax for v in self.variables]
if len(self.variables) == 1: if len(self.variables) == 1:
self._totalBias[-1] = self._totalBias[0] self._totalBias[-1] = self._totalBias[0]
self._table.setFunctionParameters(self._totalBias.flatten(), mins[0], maxs[0]) self._table.setFunctionParameters(self._totalBias.flatten(), mins[0], maxs[0])
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment