Skip to content

Commit

Permalink
Merge pull request #84 from jchodera/remove-alchemical-testsystems
Browse files Browse the repository at this point in the history
Removed alchemically modified systems, which are now tested as part of Yank
  • Loading branch information
jchodera committed Aug 24, 2015
2 parents 06f5aeb + f6a02cb commit 9fee1e5
Show file tree
Hide file tree
Showing 5 changed files with 13 additions and 328 deletions.
10 changes: 5 additions & 5 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ environment:
CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\devtools\\appveyor\\run_with_env.cmd"

matrix:
- PYTHON: "C:\\Python33_32"
PYTHON_VERSION: "3.3"
PYTHON_ARCH: "32"
CONDA_PY: "33"
CONDA_NPY: "19"
#- PYTHON: "C:\\Python33_32"
# PYTHON_VERSION: "3.3"
# PYTHON_ARCH: "32"
# CONDA_PY: "33"
# CONDA_NPY: "19"

- PYTHON: "C:\\Python34_32"
PYTHON_VERSION: "3.4"
Expand Down
10 changes: 5 additions & 5 deletions devtools/appveyor/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function InstallMiniconda ($python_version, $architecture, $python_home) {
$install_log = $python_home + ".log"
$args = "/S /D=$python_home"
Write-Host $filepath $args
Start-Process -FilePath $filepath -ArgumentList $args -Wait
Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru
if (Test-Path $python_home) {
Write-Host "Python $python_version ($architecture) installation complete"
} else {
Expand All @@ -73,17 +73,17 @@ function InstallMiniconda ($python_version, $architecture, $python_home) {

function InstallCondaPackages ($python_home, $spec) {
$conda_path = $python_home + "\Scripts\conda.exe"
$args = "install --yes --quiet $spec"
$args = "install --yes " + $spec
Write-Host ("conda " + $args)
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
}

function UpdateConda ($python_home) {
$conda_path = $python_home + "\Scripts\conda.exe"
Write-Host "Updating conda..."
$args = "update --yes --quiet conda"
$args = "update --yes conda"
Write-Host $conda_path $args
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
}


Expand Down
2 changes: 2 additions & 0 deletions devtools/conda-recipe/bld.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"%PYTHON%" setup.py install
if errorlevel 1 exit 1
2 changes: 0 additions & 2 deletions devtools/conda-recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ requirements:
- nose
- setuptools
- openmm
- jinja2
- parmed

run:
Expand All @@ -27,7 +26,6 @@ requirements:
- openmm
- nose
- setuptools
- jinja2
- six
- parmed

Expand Down
317 changes: 1 addition & 316 deletions openmmtools/testsystems.py
Original file line number Diff line number Diff line change
Expand Up @@ -3339,321 +3339,6 @@ def __init__(self, **kwargs):
self.topology = pdbfile.topology
self.system, self.positions = system, positions

#=============================================================================================
# ALCHEMICALLY MODIFIED SYSTEMS
#=============================================================================================


class AlchemicalState(object):

"""
Alchemical state description.
These parameters describe the parameters that affect computation of the energy.
Attributes
----------
relativeRestraints : float
Scaling factor for remaining receptor-ligand relative restraint terms (to help keep ligand near protein).
ligandElectrostatics : float
Scaling factor for ligand charges, intrinsic Born radii, and surface area term.
ligandSterics : float
Scaling factor for ligand sterics (Lennard-Jones and Halgren) interactions.
ligandTorsions : float
Scaling factor for ligand non-ring torsions.
annihilateElectrostatics : bool
If True, electrostatics should be annihilated, rather than decoupled.
annihilateSterics : bool
If True, sterics (Lennard-Jones or Halgren potential) will be annihilated, rather than decoupled.
TODO
----
* Rework these structure members into something more general and flexible?
* Add receptor modulation back in?
"""

def __init__(self, relativeRestraints=0.0, ligandElectrostatics=1.0, ligandSterics=1.0, ligandTorsions=1.0, annihilateElectrostatics=True, annihilateSterics=False):
"""
Create an Alchemical state.
Parameters
----------
relativeRestraints : float, optional, default = 0.0
Scaling factor for remaining receptor-ligand relative restraint terms (to help keep ligand near protein).
ligandElectrostatics : float, optional, default = 1.0
Scaling factor for ligand charges, intrinsic Born radii, and surface area term.
ligandSterics : float, optional, default = 1.0
Scaling factor for ligand sterics (Lennard-Jones or Halgren) interactions.
ligandTorsions : float, optional, default = 1.0
Scaling factor for ligand non-ring torsions.
annihilateElectrostatics : bool, optional, default = True
If True, electrostatics should be annihilated, rather than decoupled.
annihilateSterics : bool, optional, default = False
If True, sterics (Lennard-Jones or Halgren potential) will be annihilated, rather than decoupled.
Examples
--------
Create a fully-interacting, unrestrained alchemical state.
>>> alchemical_state = AlchemicalState(relativeRestraints=0.0, ligandElectrostatics=1.0, ligandSterics=1.0, ligandTorsions=1.0)
>>> # This is equivalent to
>>> alchemical_state = AlchemicalState()
Annihilate electrostatics.
>>> alchemical_state = AlchemicalState(annihilateElectrostatics=True, ligandElectrostatics=0.0)
"""

self.relativeRestraints = relativeRestraints
self.ligandElectrostatics = ligandElectrostatics
self.ligandSterics = ligandSterics
self.ligandTorsions = ligandTorsions
self.annihilateElectrostatics = annihilateElectrostatics
self.annihilateSterics = annihilateSterics

return


class AlchemicalTestSystem(object):

def _alchemicallyModifyLennardJones(cls, system, nonbonded_force, alchemical_atom_indices, alchemical_state, alpha=0.50, a=1, b=1, c=6):
"""
Alchemically modify the Lennard-Jones force terms.
This version uses the new group-based restriction capabilities of CustomNonbondedForce.
Parameters
----------
system : simtk.openmm.System
System to modify.
nonbonded_force : simtk.openmm.NonbondedForce
The NonbondedForce to modify (will be changed).
alchemical_atom_indices : list of int
Atom indices to be alchemically modified.
alchemical_state : AlchemicalState
The alchemical state specification to be used in modifying Lennard-Jones terms.
alpha : float, optional, default = 0.5
Alchemical softcore parameter.
a, b, c : float, optional, default a=1, b=1, c=6
Parameters describing softcore force.
"""

import simtk.openmm as openmm

# Create CustomNonbondedForce to handle softcore interactions between alchemically-modified system and rest of system.

energy_expression = "4*epsilon*(lambda^a)*x*(x-1.0);"
energy_expression += "x = (1.0/(alpha*(1.0-lambda)^b + (r/sigma)^c))^(6/c);"
energy_expression += "epsilon = sqrt(epsilon1*epsilon2);" # mixing rule for epsilon
energy_expression += "sigma = 0.5*(sigma1 + sigma2);" # mixing rule for sigma
energy_expression += "lambda = testsystems_AlchemicalTestSystem_lennard_jones_lambda;" # lambda

# Create atom groups.
atomset1 = set(alchemical_atom_indices) # only alchemically-modified atoms
atomset2 = set(range(system.getNumParticles())) - atomset1 # all atoms minus intra-alchemical region

# Create alchemically modified nonbonded force.
# TODO: Create a _createCustomNonbondedForce method to duplicate parameters?
energy_expression += "alpha = %f;" % alpha
energy_expression += "a = %f; b = %f; c = %f;" % (a, b, c)
custom_nonbonded_force = openmm.CustomNonbondedForce(energy_expression)
custom_nonbonded_force.setNonbondedMethod(nonbonded_force.getNonbondedMethod()) # TODO: Make sure these method indices are identical.
custom_nonbonded_force.setUseSwitchingFunction(nonbonded_force.getUseSwitchingFunction())
custom_nonbonded_force.setSwitchingDistance(nonbonded_force.getSwitchingDistance())
custom_nonbonded_force.setUseLongRangeCorrection(nonbonded_force.getUseDispersionCorrection())
custom_nonbonded_force.addGlobalParameter("testsystems_AlchemicalTestSystem_lennard_jones_lambda", alchemical_state.ligandSterics)
custom_nonbonded_force.addPerParticleParameter("sigma") # Lennard-Jones sigma
custom_nonbonded_force.addPerParticleParameter("epsilon") # Lennard-Jones epsilon

# Restrict interaction evaluation to be between alchemical atoms and rest of environment.
# Only add custom nonbonded force if interacting groups are both nonzero in size.
if (len(atomset1) != 0) and (len(atomset2) != 0):
custom_nonbonded_force.addInteractionGroup(atomset1, atomset2)
system.addForce(custom_nonbonded_force)

# Create CustomBondedForce to handle softcore exceptions if alchemically annihilating ligand.
if alchemical_state.annihilateSterics:
energy_expression = "4*epsilon*(lambda^a)*x*(x-1.0);"
energy_expression += "x = (1.0/(alpha*(1.0-lambda)^b + (r/sigma)^c))^(6/c);"
energy_expression += "alpha = %f;" % alpha
energy_expression += "a = %f; b = %f; c = %f;" % (a, b, c)
energy_expression += "lambda = testsystems_AlchemicalTestSystem_lennard_jones_lambda;"
custom_bond_force = openmm.CustomBondForce(energy_expression)
custom_bond_force.addGlobalParameter("lennard_jones_lambda", alchemical_state.ligandSterics)
custom_bond_force.addPerBondParameter("sigma") # Lennard-Jones sigma
custom_bond_force.addPerBondParameter("epsilon") # Lennard-Jones epsilon
system.addForce(custom_bond_force)
else:
# Decoupling of sterics.
# Add a second CustomNonbondedForce to restore "intra-alchemical" interactions to full strength.
energy_expression = "4*epsilon*((sigma/r)^12 - (sigma/r)^6);"
energy_expression += "epsilon = sqrt(epsilon1*epsilon2);" # mixing rule for epsilon
energy_expression += "sigma = 0.5*(sigma1 + sigma2);" # mixing rule for sigma
custom_nonbonded_force2 = openmm.CustomNonbondedForce(energy_expression)
custom_nonbonded_force2.setUseSwitchingFunction(nonbonded_force.getUseSwitchingFunction())
custom_nonbonded_force2.setSwitchingDistance(nonbonded_force.getSwitchingDistance())
custom_nonbonded_force2.setUseLongRangeCorrection(nonbonded_force.getUseDispersionCorrection())
custom_nonbonded_force2.addPerParticleParameter("sigma") # Lennard-Jones sigma
custom_nonbonded_force2.addPerParticleParameter("epsilon") # Lennard-Jones epsilon
system.addForce(custom_nonbonded_force2)
# Restrict interaction evaluation to be between alchemical atoms and rest of environment.
atomset1 = set(alchemical_atom_indices) # only alchemically-modified atoms
atomset2 = set(alchemical_atom_indices) # only alchemically-modified atoms
custom_nonbonded_force2.addInteractionGroup(atomset1, atomset2)

# Copy Lennard-Jones particle parameters.
for particle_index in range(nonbonded_force.getNumParticles()):
# Retrieve parameters.
[charge, sigma, epsilon] = nonbonded_force.getParticleParameters(particle_index)
# Add corresponding particle to softcore interactions.
if particle_index in alchemical_atom_indices:
# Turn off Lennard-Jones contribution from alchemically-modified particles.
nonbonded_force.setParticleParameters(particle_index, charge, sigma, epsilon * 0.0)
# Add contribution back to custom force.
custom_nonbonded_force.addParticle([sigma, epsilon])
if not alchemical_state.annihilateSterics:
custom_nonbonded_force2.addParticle([sigma, epsilon])

# Create an exclusion for each exception in the reference NonbondedForce, assuming that NonbondedForce will handle them.
for exception_index in range(nonbonded_force.getNumExceptions()):
# Retrieve parameters.
[iatom, jatom, chargeprod, sigma, epsilon] = nonbonded_force.getExceptionParameters(exception_index)
# Exclude this atom pair in CustomNonbondedForce.
custom_nonbonded_force.addExclusion(iatom, jatom)
if not alchemical_state.annihilateSterics:
custom_nonbonded_force2.addExclusion(iatom, jatom)

# If annihilating Lennard-Jones, move intramolecular interactions to custom_bond_force.
if alchemical_state.annihilateSterics and (iatom in alchemical_atom_indices) and (jatom in alchemical_atom_indices):
# Remove Lennard-Jones exception.
nonbonded_force.setExceptionParameters(exception_index, iatom, jatom, chargeprod, sigma, epsilon * 0.0)
# Add special CustomBondForce term to handle alchemically-modified Lennard-Jones exception.
custom_bond_force.addBond(iatom, jatom, [sigma, epsilon])

# Set periodicity and cutoff parameters corresponding to reference Force.
if nonbonded_force.getNonbondedMethod() in [openmm.NonbondedForce.Ewald, openmm.NonbondedForce.PME]:
# Convert Ewald and PME to CutoffPeriodic.
custom_nonbonded_force.setNonbondedMethod(openmm.CustomNonbondedForce.CutoffPeriodic)
if not alchemical_state.annihilateSterics:
custom_nonbonded_force2.setNonbondedMethod(openmm.CustomNonbondedForce.CutoffPeriodic)
else:
custom_nonbonded_force.setNonbondedMethod(nonbonded_force.getNonbondedMethod())
if not alchemical_state.annihilateSterics:
custom_nonbonded_force2.setNonbondedMethod(nonbonded_force.getNonbondedMethod())

custom_nonbonded_force.setCutoffDistance(nonbonded_force.getCutoffDistance())
if not alchemical_state.annihilateSterics:
custom_nonbonded_force2.setCutoffDistance(nonbonded_force.getCutoffDistance())

return


class AlchemicalLennardJonesCluster(TestSystem, AlchemicalTestSystem):

"""Create an alchemically-perturbed version of LennardJonesCluster.
Parameters
----------
nx : int, optional, default=3
number of particles in the x direction
ny : int, optional, default=3
number of particles in the y direction
nz : int, optional, default=3
number of particles in the z direction
K : simtk.unit.Quantity, optional, default=1.0 * unit.kilojoules_per_mole/unit.nanometer**2
harmonic restraining potential
Examples
--------
Create Lennard-Jones cluster.
>>> cluster = AlchemicalLennardJonesCluster()
>>> system, positions = cluster.system, cluster.positions
Create default 3x3x3 Lennard-Jones cluster in a harmonic restraining potential.
>>> cluster = AlchemicalLennardJonesCluster(nx=10, ny=10, nz=10)
>>> system, positions = cluster.system, cluster.positions
"""

def __init__(self, nx=3, ny=3, nz=3, K=1.0 * unit.kilojoules_per_mole / unit.nanometer**2, **kwargs):

TestSystem.__init__(self, **kwargs)

# Default parameters
mass_Ar = 39.9 * unit.amu
q_Ar = 0.0 * unit.elementary_charge
sigma_Ar = 3.350 * unit.angstrom
epsilon_Ar = 0.001603 * unit.kilojoule_per_mole

scaleStepSizeX = 1.0
scaleStepSizeY = 1.0
scaleStepSizeZ = 1.0

# Determine total number of atoms.
natoms = nx * ny * nz

# Create an empty system object.
system = openmm.System()

# Create a NonbondedForce object with no cutoff.
nb = openmm.NonbondedForce()
nb.setNonbondedMethod(openmm.NonbondedForce.NoCutoff)

positions = unit.Quantity(np.zeros([natoms, 3], np.float32), unit.angstrom)

atom_index = 0
for ii in range(nx):
for jj in range(ny):
for kk in range(nz):
system.addParticle(mass_Ar)
nb.addParticle(q_Ar, sigma_Ar, epsilon_Ar)
x = sigma_Ar * scaleStepSizeX * (ii - nx / 2.0)
y = sigma_Ar * scaleStepSizeY * (jj - ny / 2.0)
z = sigma_Ar * scaleStepSizeZ * (kk - nz / 2.0)

positions[atom_index, 0] = x
positions[atom_index, 1] = y
positions[atom_index, 2] = z
atom_index += 1

# Add the nonbonded force.
system.addForce(nb)

# Add a restrining potential centered at the origin.
energy_expression = "(K/2.0) * (x^2 + y^2 + z^2);"
energy_expression += "K = testsystems_AlchemicalLennardJonesCluster_K;"
force = openmm.CustomExternalForce(energy_expression)
force.addGlobalParameter('testsystems_AlchemicalLennardJonesCluster_K', K)
for particle_index in range(natoms):
force.addParticle(particle_index, [])
system.addForce(force)

# Alchemically modify system.
alchemical_atom_indices = [0]
delta = 1.0e-5
alchemical_state = AlchemicalState(0, 0, 1 - delta, 1, annihilateElectrostatics=True, annihilateSterics=False)
self._alchemicallyModifyLennardJones(system, nb, alchemical_atom_indices, alchemical_state)

# Create topology.
topology = app.Topology()
element = app.Element.getBySymbol('Ar')
chain = topology.addChain()
for particle in range(system.getNumParticles()):
residue = topology.addResidue('Ar', chain)
topology.addAtom('Ar', element, residue)

self.system, self.positions, self.topology = system, positions, topology


#=============================================================================================
# BINDING FREE ENERGY TESTS
#=============================================================================================
Expand Down Expand Up @@ -3731,7 +3416,7 @@ def __init__(self, mass=39.9 * unit.amu, sigma=3.350 * unit.angstrom, epsilon=10

# Create second particle.
system.addParticle(mass)
force.addParticle(-charge, sigma, epsilon)
force.addParticle(charge, sigma, epsilon)

# Add the nonbonded force.
system.addForce(force)
Expand Down

0 comments on commit 9fee1e5

Please sign in to comment.