sample.py
sample.py
from Sire.IO import *
from Sire.Squire import *
from Sire.MM import *
from Sire.Mol import *
from Sire.Move import *
from Sire.System import *
from Sire.Maths import *
from Sire.CAS import *
from Sire.Units import *
import os
import sys
import math
# Get the name of the solute from the first
# command line argument (should be 'PHE' or 'TRP')
molname = sys.argv[1]
# Load the solute in a box of water, together with the
# information about the periodic box
(mols, space) = Amber().readCrdTop("%s.crd" % molname, "%s.top" % molname)
# pick out the solute from the box of molecules
mol = mols[ MolWithResID(molname) ].molecule()
# now get all of the waters (every molecule except the solute)
waters = mols.molecules()
waters.remove(mol)
# Set the cutoff distance as 10 angstroms
cutoff = HarmonicSwitchingFunction( 10 * angstrom )
# Create an MM forcefield to calculate the
# MM electrostatic energy between the solute and the waters
mmff = InterGroupCLJFF("mmff")
mmff.setSwitchingFunction(cutoff)
mmff.setSpace(space)
# Create a QM/MM forcefield to calculate the QM/MM
# electrostatic energy between the solute and the waters
qmmmff = QMMMFF("qmmmff")
qmmmff.setSwitchingFunction(cutoff)
qmmmff.setSpace(space)
qmmmff.setIntermolecularOnly(True)
# We will use the SQM program to calculate QM energies.
# Create the program and set the semi-empirical method
# from the passed string
qmprog = SQM()
qmprog.setMethod(sys.argv[2])
# Tell qmprog where to find the SQM executable
amberhome = os.getenv("AMBERHOME")
if amberhome is None:
print("Please set the AMBERHOME environment variable to point")
print("to the Amber14 installation.")
sys.exit(-1)
qmprog.setExecutable( "%s/bin/sqm" % amberhome )
# Tell the QM/MM forcefield to use this program
qmmmff.setQuantumProgram(qmprog)
# Now add the solute to group 0 of both forcefields
mmff.add( mol, MGIdx(0) )
qmmmff.add( mol, MGIdx(0) )
# Now add the waters to group 1 of both forcefields
mmff.add( waters, MGIdx(1) )
qmmmff.add( waters, MGIdx(1) )
# New stuff :-)
# we need a forcefield to hold the intermolecular
# energy between the water molecules
waterff = InterCLJFF("waterff")
waterff.setSwitchingFunction(cutoff)
waterff.setSpace(space)
waterff.add(waters)
# Now add all of the forcefields together into a single
# simulation system
system = System()
watergroup = MoleculeGroup("waters")
watergroup.add(waters)
system.add(watergroup)
system.add(mmff)
system.add(qmmmff)
system.add(waterff)
# Define the total MM energy
e_mm = Symbol("E_MM")
e_qmmm = Symbol("E_QMMM")
system.setComponent( e_mm, mmff.components().total() + \
waterff.components().total() )
system.setComponent( e_qmmm, qmmmff.components().total() + \
mmff.components().lj() + \
waterff.components().total() )
# also define the difference in energy
e_diff = Symbol("E_diff")
system.setComponent( e_diff, e_mm - e_qmmm )
# Now add a monitor that will record the average of the
# difference in energy between QM/MM and MM
system.add( "difference", MonitorComponent(e_diff, Average()) )
# now print out the QM/MM energy, MM energy and difference
print("Total QM/MM energy = %s" % system.energy(e_qmmm))
print("Total MM energy = %s" % system.energy(e_mm))
print("Difference = %s" % system.energy(e_diff))
# create a random number generator for the simulation
rand = RanGenerator()
# now create a function to run one multiple-timestep
# Monte Carlo move (using 5000 fast MM moves)
def multiMCMove(system, nfast=5000):
# calculate the old QM/MM and MM energies
old_qmmm = system.energy(e_qmmm).value()
old_mm = system.energy(e_mm).value()
# Save the old conformation of the system
old_system = System(system)
# now perform 'nfast' MC moves using the
# MM potential
move = RigidBodyMC(watergroup)
move.setEnergyComponent(e_mm)
# actually perform the moves
move.move(system, nfast, False)
# calculate the new QM/MM and MM energies
new_qmmm = system.energy(e_qmmm).value()
new_mm = system.energy(e_mm).value()
# now use the multiple timestep MC test
# to accept or reject the move (at 298 K)
beta = 1.0 / (k_boltz * 298.0)
test = math.exp( -beta * ( (new_qmmm - new_mm) - \
(old_qmmm - old_mm) ) )
print("E_QMMM(new) - E_MM(new) = %.2f" % (new_qmmm - new_mm))
print("E_QMMM(old) - E_MM(old) = %.2f" % (old_qmmm - old_mm))
print("(E_QMMM(new)-E_MM(new)) - (E_QMMM(old)-E_MM(old)) = %.2f" % \
((new_qmmm-new_mm) - (old_qmmm - old_mm)) )
print("exp{-beta * [(E_QMMM(new)-E_MM(new)) - (E_QMMM(old)-E_MM(old)]} = %.2f" % \
test )
randnum = rand.rand()
print("Random number between 0 and 1 = %.2f" % randnum)
if randnum < test:
print("Random number is smaller: Move accepted!")
# record the average difference
system.collectStats()
return system
else:
print("Random number is larger: Move rejected!")
# record the average difference
system.collectStats()
return old_system
# perform 20 multiple timestep MC moves
for i in range(1,21):
print("\nPerforming move %d" % i)
system = multiMCMove(system)
PDB().write(system.molecules(), "coords%003d.pdb" % i)
# print the average energy difference
avg_diff = system[ MonitorName("difference") ].accumulator().average()
print("\nTotal QM/MM energy = %s" % system.energy(e_qmmm))
print("Total MM energy = %s" % system.energy(e_mm))
print("Difference = %s" % system.energy(e_diff))
print("\nCoordinates saved to 'coords*.pdb'")
print("\nAverage energy difference = %s kcal mol-1" % avg_diff)