def _interpolation_grid_force(self): self._widths = [] self._bounds = [] self._extra_points = [] for v in self.bias_variables: extra_points = min(self.grid_expansion, v.grid_size) if v.periodic else 0 extra_range = extra_points*v._range/(v.grid_size - 1) self._widths.append(v.grid_size + 2*extra_points) self._bounds += [v.min_value - extra_range, v.max_value + extra_range] self._extra_points.append(extra_points) self._bias = np.zeros(np.prod(self._widths)) num_bias_variables = len(self.bias_variables) if num_bias_variables == 1: self._table = openmm.Continuous1DFunction(self._bias, *self._bounds) elif num_bias_variables == 2: self._table = openmm.Continuous2DFunction(*self._widths, self._bias, *self._bounds) else: self._table = openmm.Continuous3DFunction(*self._widths, self._bias, *self._bounds) expression = f'bias({",".join(v.id for v in self.bias_variables)})' for i, v in enumerate(self.bias_variables): expression += f';{v.id}={v._get_energy_function(i+1)}' force = openmm.CustomCVForce(expression) for i in range(num_bias_variables): x = openmm.CustomExternalForce('x') x.addParticle(0, []) force.addCollectiveVariable(f'x{i+1}', x) force.addTabulatedFunction('bias', self._table) force.addGlobalParameter('Lx', 0) return force
def get_Upair_force(Ucg, coeff, r_vals): """Create pairwise potentials as tabulated functions""" N = Ucg.n_atoms bcut = Ucg.bond_cutoff Up_vals = Ucg.Upair_values(coeff, r_vals) if len(Up_vals) > 1: table_vals = np.zeros((len(Up_vals), len(r_vals))) for i in range(len(Up_vals)): table_vals[i,:] = Up_vals[i] xvals = np.arange(len(Up_vals)).astype(float) yvals = r_vals Table_func = omm.Continuous2DFunction(len(xvals), len(yvals), table_vals.flatten(), xvals[0], xvals[-1], yvals[0], yvals[-1]) Up_force = omm.CustomCompoundBondForce(2, "Table(p_idx, distance(p1, p2))") Up_force.addPerBondParameter("p_idx") Up_force.addTabulatedFunction("Table", Table_func) else: Table_func = omm.Continuous1DFunction(Up_vals[0], r_vals[0], r_vals[-1]) Up_force = omm.CustomCompoundBondForce(2, "Table(distance(p1, p2))") Up_force.addTabulatedFunction("Table", Table_func) if Ucg.pair_symmetry == "shared": # all pairs share same interaction for i in range(N - bcut): for j in range(i + bcut, N): Up_force.addBond((i, j)) elif Ucg.pair_symmetry == "seq_sep": # pairs with same sequence sep share same interaction for i in range(N - bcut): for j in range(i + bcut, N): p_idx = np.abs(j - i) - bcut Up_force.addBond([i, j], p_idx) elif Ucg.pair_symmetry == "unique": # all pair have different interactions p_idx = 0 for i in range(N - bcut): for j in range(i + bcut, N): Up_force.addBond((i, j), (p_idx)) p_idx += 1 else: raise ValueError("pair_symmetry must be: shared, seq_sep, unique. Gave:" + str(Ucg.pair_symmetry)) return Up_force
def __init__(self, variables, height, frequency, grid_expansion): self.bias_variables = [cv for cv in variables if cv.sigma is not None] self.height = height self.frequency = frequency self.grid_expansion = grid_expansion self._widths = [] self._bounds = [] self._expanded = [] self._extra_points = [] for cv in self.bias_variables: expanded = cv.periodic # and len(self.bias_variables) > 1 extra_points = min(grid_expansion, cv.grid_size) if expanded else 0 extra_range = extra_points * cv._range / (cv.grid_size - 1) self._widths += [cv.grid_size + 2 * extra_points] self._bounds += [ cv.min_value - extra_range, cv.max_value + extra_range ] self._expanded += [expanded] self._extra_points += [extra_points] self._bias = np.zeros(tuple(reversed(self._widths))) if len(variables) == 1: self._table = openmm.Continuous1DFunction( self._bias.flatten(), *self._bounds, # self.bias_variables[0].periodic, ) elif len(variables) == 2: self._table = openmm.Continuous2DFunction( *self._widths, self._bias.flatten(), *self._bounds, ) elif len(variables) == 3: self._table = openmm.Continuous3DFunction( *self._widths, self._bias.flatten(), *self._bounds, ) else: raise ValueError( 'UFED requires 1, 2, or 3 biased collective variables') parameter_list = ', '.join(f's_{cv.id}' for cv in self.bias_variables) self.force = openmm.CustomCVForce(f'bias({parameter_list})') for cv in self.bias_variables: expression = f'{cv.min_value}+{cv._range}*(x/Lx-floor(x/Lx))' parameter = openmm.CustomExternalForce(expression) parameter.addGlobalParameter('Lx', 0.0) parameter.addParticle(0, []) self.force.addCollectiveVariable(f's_{cv.id}', parameter) self.force.addTabulatedFunction('bias', self._table)
def __init__(self, system, variables, temperature, biasFactor, height, frequency, saveFrequency=None, biasDir=None): """Create a Metadynamics object. Parameters ---------- system: System the System to simulate. A CustomCVForce implementing the bias is created and added to the System. variables: list of BiasVariables the collective variables to sample temperature: temperature the temperature at which the simulation is being run. This is used in computing the free energy. biasFactor: float used in scaling the height of the Gaussians added to the bias. The collective variables are sampled as if the effective temperature of the simulation were temperature*biasFactor. height: energy the initial height of the Gaussians to add frequency: int the interval in time steps at which Gaussians should be added to the bias potential saveFrequency: int (optional) the interval in time steps at which to write out the current biases to disk. At the same time it writes biases, it also checks for updated biases written by other processes and loads them in. This must be a multiple of frequency. biasDir: str (optional) the directory to which biases should be written, and from which biases written by other processes should be loaded """ if not unit.is_quantity(temperature): temperature = temperature * unit.kelvin if not unit.is_quantity(height): height = height * unit.kilojoules_per_mole if biasFactor < 1.0: raise ValueError('biasFactor must be >= 1') if (saveFrequency is None and biasDir is not None) or (saveFrequency is not None and biasDir is None): raise ValueError('Must specify both saveFrequency and biasDir') if saveFrequency is not None and (saveFrequency < frequency or saveFrequency % frequency != 0): raise ValueError('saveFrequency must be a multiple of frequency') self.variables = variables self.temperature = temperature self.biasFactor = biasFactor self.height = height self.frequency = frequency self.biasDir = biasDir self.saveFrequency = saveFrequency self._id = np.random.randint(0x7FFFFFFF) self._saveIndex = 0 self._selfBias = np.zeros(tuple(v.gridWidth for v in variables)) self._totalBias = np.zeros(tuple(v.gridWidth for v in variables)) self._loadedBiases = {} self._deltaT = temperature * (biasFactor - 1) varNames = ['cv%d' % i for i in range(len(variables))] self._force = mm.CustomCVForce('table(%s)' % ', '.join(varNames)) for name, var in zip(varNames, variables): self._force.addCollectiveVariable(name, var.force) widths = [v.gridWidth for v in variables] mins = [v.minValue for v in variables] maxs = [v.maxValue for v in variables] if len(variables) == 1: self._table = mm.Continuous1DFunction(self._totalBias.flatten(), mins[0], maxs[0]) elif len(variables) == 2: self._table = mm.Continuous2DFunction(widths[0], widths[1], self._totalBias.flatten(), mins[0], maxs[0], mins[1], maxs[1]) elif len(variables) == 3: self._table = mm.Continuous3DFunction(widths[0], widths[1], widths[2], self._totalBias.flatten(), mins[0], maxs[0], mins[1], maxs[1], mins[2], maxs[2]) else: raise ValueError( 'Metadynamics requires 1, 2, or 3 collective variables') self._force.addTabulatedFunction('table', self._table) self._force.setForceGroup(31) system.addForce(self._force) self._syncWithDisk()