Open matteo-ambrosetti opened 4 years ago
Hi @matteo-ambrosetti,
I'm not sure exactly what you're looking to do. Could you describe your question a bit more?
A few general ways that we interact with charges are
charge_from_molecules
kwarg to create_openmm_system
, which will apply the charges from molecule.partial_charges
to every instance of that molecule in the final systemopenmm.NonbondedForce.getParticleParameters
. You can retrieve an existing System's NonbondedForce
object using code like here: https://github.com/openforcefield/openforcefield/blob/master/openforcefield/typing/engines/smirnoff/parameters.py#L3298-L3302, and then you can investigate/manipulate the charges and vdW parameters using code like here: https://github.com/openforcefield/openforcefield/blob/master/openforcefield/typing/engines/smirnoff/parameters.py#L2702-L2707Let me know if either of these solve your problem, otherwise we can discuss other possibilities for your specific needs.
Yes, sorry, it was a quite dry question...
I was referring to the fluctuating charge force field (see https://aip.scitation.org/doi/pdf/10.1063/1.468398). The main difference with respect to a "standard" MD is in the ability of charges to fluctuate as a response to the environment. I have already implemented a code to compute the equilibrium charges and I was thinking to interface it with OpenMM. Since the atomic charges should change according to the system's geometry during the dynamics, I need to update them every time step.
Ah, I see. Right now the Open Force Field Toolkit does not support parameterizing systems with fluctuating charges. In the future, we may begin offering support for certain polarizability models that are supported by OpenMM. This isn't on our development roadmap yet, so I can not provide a date for when that will be ready. If you're interested in adding it, I'd be happy to guide you through its implementation, though it would probably take a few weeks.
That would be great, I am interested in adding it! I have been using the fluctuating charge (FQ) force field in the context of QM/MM models so far (relying on fixed charge FFs for the sampling part). I think that being able to perform a FQ-MD would be highly beneficial to my research.
@matteo-ambrosetti we have no objection in principle to including FlucQ models; a big picture goal is to enable our toolkit/suite to support all the different types of force fields people might be interested in using so that they all can be parameterized/compared on equal footing.
[Note: I updated the above; I left out the word "no" in "no objection" in the first post in error.]
I think critical milestones to achieving this would be things like:
I hope that helps!
Thanks @davidlmobley, I will keep your suggestion in mind. This is the first time I deal with a code like this, so suggestions and help are welcomed! I will start by checking if the science needed is supported (I know for sure that CHARMM already supports FQ).
Sounds good, @matteo-ambrosetti.
A bit of introduction for @davidlmobley's item 1: Right now we natively produce parameterized systems in OpenMM's System
format, mostly because it has the highest information content of any MM file format (this lets us convert to other formats via ParmEd easily, since we're almost always removing information, rather than needing to guess it). Architecturally, this means that our parameterization routine is performed by the ForceField.create_openmm_system
function. So, the most important thing is that we be able to write fluctuating charges into an OpenMM System
object. The first step to that is to ensure that we can implement the fluctuating charge model into an OpenMM Force
object (perhaps a CustomNonbondedForce offers enough flexibility to implement fluctuating charges?).
The step after that will be seeing if it'll be possible to convert this fluctuating charge model from an OpenMM force into other packages (like CHARMM). We usually handle this using ParmEd, but since this will be a new functional form, I don't think that ParmEd supports this conversion yet. So we'll need to add this if we want to simulate outside OpenMM.
Anyway, I'd be interested to know if the fluctuating charges model can be computed in OpenMM -- Please update us as you look into that!
Right, an addendum to Jeff's point is that it's also important to know whether the CHARMM, AMBER and OpenMM packages can all support the SAME type of FlucQ model that you want to implement, so that moving it into all packages would just be an issue of conversion. Otherwise, broad support gets more complicated.
That wouldn't mean you couldn't proceed, but it would just affect how one would go about it.
From what I got from literature the Fluctuating Charge (FQ) Force Field (FF) is implemented only in CHARMM. The principal differences with respect to a non-polarizable molecular dynamics are:
Electrostatic interaction
Dynamics
The only implementation of a polarizable FF is the one reported in the first article on ForceBalance, but the model implemented is the QTPIE which differs from FQ.
I don't know if it is a good idea or not, but I am trying to set up a first (wrong) attempt just to see if I have everything I need. The code is something like this:
for step in range(num_steps):
# 1. Evolve the system of one step
sim.step(1)
# 2. Compute the charges of each atom based on the new geometry
# 3. Assign them to the corresponding atom
I am experiencing some problem with the third step, the update of the charges. Indeed, if I increase the charges at each step nothing seems to change in the energy. I attach an example of the code.
import simtk.openmm as omm
import simtk.openmm.app as app
import simtk.unit as unit
import openforcefield.topology as off_top
from openforcefield.typing.engines.smirnoff import ForceField
import numpy as np
# Read input geometry
pdbfile = app.PDBFile("water_box.pdb")
omm_topology = pdbfile.topology
# Water
solvent = off_top.Molecule.from_smiles('O')
# System
all_system = [solvent]
# Create the Open Force Field Topology from an OpenMM Topology object.
off_topology = off_top.Topology.from_openmm(openmm_topology=omm_topology, unique_molecules=all_system)
# Load the OpenFF "Parsley" force field.
forcefield = ForceField('openff-1.1.0.offxml')
# Parametrize the topology and create an OpenMM System.
system = forcefield.create_openmm_system(off_topology, charge_from_molecules=all_system)
# Propagate the System with Langevin dynamics.
time_step = 2*unit.femtoseconds # simulation timestep
temperature = 300*unit.kelvin # simulation temperature
friction = 1/unit.picosecond # collision rate
num_steps = 10000 # number of integration steps to run
# Output options.
trj_freq = 1 # int(num_steps/1000) # number of steps per written trajectory frame
data_freq = 1 # int(num_steps/100) # number of steps per written simulation statistics
# System setup.
nonbonded_method = app.PME
nonbonded_cutoff = 8.0*unit.angstroms
constraints = app.HBonds #None, app.HBonds, app.AllBonds
# Define the platform to use; CUDA, OpenCL, CPU, or Reference. Or do not specify
# the platform to use the default (fastest) platform
platform = omm.Platform.getPlatformByName('CPU')
# Parametrize the topology and create an OpenMM System.
system = forcefield.create_openmm_system(off_topology, charge_from_molecules=all_system)
# Create the integrator to do Langevin dynamics
integrator = omm.LangevinIntegrator(temperature, friction, time_step)
# Create the Simulation object
sim = app.Simulation(omm_topology, system, integrator, platform)
# System positions
positions = pdbfile.getPositions()
# Set the particle positions
sim.context.setPositions(positions)
# Randomize the velocities from a Boltzmann distribution at a given temperature.
sim.context.setVelocitiesToTemperature(temperature)
# Minimize the energy
print('Minimizing energy...')
sim.minimizeEnergy(maxIterations=500)
print("Energy minimization complete.")
# Set up the reporters to report energies and coordinates every 100 steps
pdb_reporter = omm.app.PDBReporter('trajectory.pdb', trj_freq)
state_data_reporter = omm.app.StateDataReporter('data.csv', data_freq, step=True,
potentialEnergy=True, temperature=True,
density=True)
sim.reporters.append(pdb_reporter)
sim.reporters.append(state_data_reporter)
for step in range(500):
# 1. Evolve the system of one step
sim.step(1)
print("Energy of the system : ", sim.context.getState(getEnergy=True).getPotentialEnergy())
# 2. Compute the charges of each atom based on the new geometry
# 3. Assign them to the corresponding atom
# Compute the forces and check their value
forces = sim.context.getState(getForces=True).getForces()
for force in system.getForces():
# Select the nonbonded forces
if isinstance(force, omm.openmm.NonbondedForce):
# Run over all the particles of the system
for j in range(system.getNumParticles()):
# Get the parameters associated to each particle
charge, sigma, epsilon = force.getParticleParameters(j)
print(charge, sigma, epsilon)
if j > 2:
new_charge = charge + 10.0e+10*unit.elementary_charge
else:
new_charge = charge - 10.0e+10*unit.elementary_charge
force.setParticleParameters(j, new_charge, sigma, epsilon)
charge, sigma, epsilon = force.getParticleParameters(j)
print(charge, sigma, epsilon)
print("New energy of the system : ", sim.context.getState(getEnergy=True).getPotentialEnergy(), "\n")
This is the geometry:
HEADER
TITLE Built with Packmol through Packmol Memgen
REMARK Packmol generated pdb file, Packmol Memgen estimated parameters
REMARK Home-Page: http://www.ime.unicamp.br/~martinez/packmol
REMARK
CRYST1 20.00 20.00 20.00 90.00 90.00 90.00 P 1 1
HETATM 1 H1 HOH A 1 7.387 12.021 11.223
HETATM 2 H2 HOH A 1 8.249 10.734 11.739
HETATM 3 O HOH A 1 7.877 11.624 12.000
HETATM 4 H1 HOH A 2 16.284 9.965 12.754
HETATM 5 H2 HOH A 2 14.923 9.105 13.028
HETATM 6 O HOH A 2 15.376 9.737 12.401
END
@matteo-ambrosetti I personally don't have the expertise with OpenMM to help you attempt this; I'd guess that the OpenMM issue tracker is the best place to follow this up, since you're dealing with whether or not you can get it to work in OpenMM.
If the answer is "yes", then you should come back over here and we can talk about how to get it working in OpenFF.
I suspect that @jchodera 's Yank package makes updates to charges on the fly, or it did at one point, so it may be worth looking there (and at their related work on Perses) to see how they do this. However, this is not in the context of fluctuating charge models but rather free energy calculations.
Hello everyone, is it possible to change the atomic charges on the fly (or is there an easy way to do it)?