Commit c7aa1d00 authored by kyleabeauchamp's avatar kyleabeauchamp
Browse files

Merge remote-tracking branch 'upstream/master' into vagrant

parents aea4e454 f7127d33
...@@ -61,7 +61,7 @@ void validateForce(System& system, vector<Vec3>& positions, double expectedEnerg ...@@ -61,7 +61,7 @@ void validateForce(System& system, vector<Vec3>& positions, double expectedEnerg
// Try moving each particle along each axis, and see if the energy changes by the correct amount. // Try moving each particle along each axis, and see if the energy changes by the correct amount.
double offset = 1e-3; double offset = 1e-2;
for (int i = 0; i < system.getNumParticles(); i++) for (int i = 0; i < system.getNumParticles(); i++)
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
vector<Vec3> offsetPos = positions; vector<Vec3> offsetPos = positions;
...@@ -76,9 +76,9 @@ void validateForce(System& system, vector<Vec3>& positions, double expectedEnerg ...@@ -76,9 +76,9 @@ void validateForce(System& system, vector<Vec3>& positions, double expectedEnerg
} }
void testSingleParticle() { void testSingleParticle() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
System system; System system;
system.addParticle(1.0); system.addParticle(1.0);
system.addParticle(1.0); system.addParticle(1.0);
...@@ -92,9 +92,9 @@ void testSingleParticle() { ...@@ -92,9 +92,9 @@ void testSingleParticle() {
} }
void testAnisotropicParticle() { void testAnisotropicParticle() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double a1 = 0.8; const double a1 = 0.8;
const double a2 = 1.1; const double a2 = 1.1;
const double k1 = k/a1; const double k1 = k/a1;
...@@ -124,9 +124,9 @@ double computeScreening(double r, double thole, double alpha1, double alpha2) { ...@@ -124,9 +124,9 @@ double computeScreening(double r, double thole, double alpha1, double alpha2) {
} }
void testThole() { void testThole() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double thole = 2.5; const double thole = 2.5;
System system; System system;
system.addParticle(1.0); system.addParticle(1.0);
...@@ -157,9 +157,9 @@ void testThole() { ...@@ -157,9 +157,9 @@ void testThole() {
} }
void testChangingParameters() { void testChangingParameters() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
Platform& platform = Platform::getPlatformByName("CUDA"); Platform& platform = Platform::getPlatformByName("CUDA");
// Create the system. // Create the system.
...@@ -184,9 +184,9 @@ void testChangingParameters() { ...@@ -184,9 +184,9 @@ void testChangingParameters() {
// Modify the parameters. // Modify the parameters.
const double k2 = 2.2; const double k2 = ONE_4PI_EPS0*2.2;
const double charge2 = 0.3; const double charge2 = 0.3;
const double alpha2 = charge2*charge2/k2; const double alpha2 = ONE_4PI_EPS0*charge2*charge2/k2;
drude->setParticleParameters(0, 1, 0, -1, -1, -1, charge2, alpha2, 1, 1); drude->setParticleParameters(0, 1, 0, -1, -1, -1, charge2, alpha2, 1, 1);
drude->updateParametersInContext(context); drude->updateParametersInContext(context);
state = context.getState(State::Energy); state = context.getState(State::Energy);
......
...@@ -53,9 +53,9 @@ extern "C" OPENMM_EXPORT void registerDrudeCudaKernelFactories(); ...@@ -53,9 +53,9 @@ extern "C" OPENMM_EXPORT void registerDrudeCudaKernelFactories();
void testSinglePair() { void testSinglePair() {
const double temperature = 300.0; const double temperature = 300.0;
const double temperatureDrude = 10.0; const double temperatureDrude = 10.0;
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double mass1 = 1.0; const double mass1 = 1.0;
const double mass2 = 0.1; const double mass2 = 0.1;
const double totalMass = mass1+mass2; const double totalMass = mass1+mass2;
...@@ -132,7 +132,7 @@ void testWater() { ...@@ -132,7 +132,7 @@ void testWater() {
system.addConstraint(startIndex, startIndex+3, 0.09572); system.addConstraint(startIndex, startIndex+3, 0.09572);
system.addConstraint(startIndex+2, startIndex+3, 0.15139); system.addConstraint(startIndex+2, startIndex+3, 0.15139);
system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721)); system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721));
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, 1.71636*1.71636/(100000*4.184), 1, 1); drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184), 1, 1);
} }
vector<Vec3> positions; vector<Vec3> positions;
for (int i = 0; i < gridSize; i++) for (int i = 0; i < gridSize; i++)
......
...@@ -85,7 +85,7 @@ void testWater() { ...@@ -85,7 +85,7 @@ void testWater() {
system.addConstraint(startIndex, startIndex+3, 0.09572); system.addConstraint(startIndex, startIndex+3, 0.09572);
system.addConstraint(startIndex+2, startIndex+3, 0.15139); system.addConstraint(startIndex+2, startIndex+3, 0.15139);
system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721)); system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721));
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, 1.71636*1.71636/(100000*4.184), 1, 1); drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184), 1, 1);
} }
vector<Vec3> positions; vector<Vec3> positions;
for (int i = 0; i < gridSize; i++) for (int i = 0; i < gridSize; i++)
......
...@@ -131,9 +131,9 @@ void OpenCLCalcDrudeForceKernel::initialize(const System& system, const DrudeFor ...@@ -131,9 +131,9 @@ void OpenCLCalcDrudeForceKernel::initialize(const System& system, const DrudeFor
double a1 = (atoms[i][2] == -1 ? 1 : aniso12); double a1 = (atoms[i][2] == -1 ? 1 : aniso12);
double a2 = (atoms[i][3] == -1 || atoms[i][4] == -1 ? 1 : aniso34); double a2 = (atoms[i][3] == -1 || atoms[i][4] == -1 ? 1 : aniso34);
double a3 = 3-a1-a2; double a3 = 3-a1-a2;
double k3 = charge*charge/(polarizability*a3); double k3 = ONE_4PI_EPS0*charge*charge/(polarizability*a3);
double k1 = charge*charge/(polarizability*a1) - k3; double k1 = ONE_4PI_EPS0*charge*charge/(polarizability*a1) - k3;
double k2 = charge*charge/(polarizability*a2) - k3; double k2 = ONE_4PI_EPS0*charge*charge/(polarizability*a2) - k3;
if (atoms[i][2] == -1) { if (atoms[i][2] == -1) {
atoms[i][2] = 0; atoms[i][2] = 0;
k1 = 0; k1 = 0;
...@@ -202,9 +202,9 @@ void OpenCLCalcDrudeForceKernel::copyParametersToContext(ContextImpl& context, c ...@@ -202,9 +202,9 @@ void OpenCLCalcDrudeForceKernel::copyParametersToContext(ContextImpl& context, c
double a1 = (p2 == -1 ? 1 : aniso12); double a1 = (p2 == -1 ? 1 : aniso12);
double a2 = (p3 == -1 || p4 == -1 ? 1 : aniso34); double a2 = (p3 == -1 || p4 == -1 ? 1 : aniso34);
double a3 = 3-a1-a2; double a3 = 3-a1-a2;
double k3 = charge*charge/(polarizability*a3); double k3 = ONE_4PI_EPS0*charge*charge/(polarizability*a3);
double k1 = charge*charge/(polarizability*a1) - k3; double k1 = ONE_4PI_EPS0*charge*charge/(polarizability*a1) - k3;
double k2 = charge*charge/(polarizability*a2) - k3; double k2 = ONE_4PI_EPS0*charge*charge/(polarizability*a2) - k3;
if (p2 == -1) if (p2 == -1)
k1 = 0; k1 = 0;
if (p3 == -1 || p4 == -1) if (p3 == -1 || p4 == -1)
......
...@@ -13,7 +13,7 @@ real u = drudeParams.x*r; ...@@ -13,7 +13,7 @@ real u = drudeParams.x*r;
real screening = 1-(1+0.5f*u)*EXP(-u); real screening = 1-(1+0.5f*u)*EXP(-u);
real pairEnergy = drudeParams.y*screening*rInv; real pairEnergy = drudeParams.y*screening*rInv;
energy += pairEnergy; energy += pairEnergy;
real4 f = delta*(pairEnergy*rInv*rInv); real4 f = delta*(drudeParams.y*rInv*rInv)*(screening*rInv-0.5f*(1+u)*EXP(-u)*drudeParams.x);
force1 += f; force1 += f;
force3 -= f; force3 -= f;
...@@ -26,7 +26,7 @@ u = drudeParams.x*r; ...@@ -26,7 +26,7 @@ u = drudeParams.x*r;
screening = 1-(1+0.5f*u)*EXP(-u); screening = 1-(1+0.5f*u)*EXP(-u);
pairEnergy = -drudeParams.y*screening*rInv; pairEnergy = -drudeParams.y*screening*rInv;
energy += pairEnergy; energy += pairEnergy;
f = delta*(pairEnergy*rInv*rInv); f = delta*(-drudeParams.y*rInv*rInv)*(screening*rInv-0.5f*(1+u)*EXP(-u)*drudeParams.x);
force1 += f; force1 += f;
force4 -= f; force4 -= f;
...@@ -39,7 +39,7 @@ u = drudeParams.x*r; ...@@ -39,7 +39,7 @@ u = drudeParams.x*r;
screening = 1-(1+0.5f*u)*EXP(-u); screening = 1-(1+0.5f*u)*EXP(-u);
pairEnergy = -drudeParams.y*screening*rInv; pairEnergy = -drudeParams.y*screening*rInv;
energy += pairEnergy; energy += pairEnergy;
f = delta*(pairEnergy*rInv*rInv); f = delta*(-drudeParams.y*rInv*rInv)*(screening*rInv-0.5f*(1+u)*EXP(-u)*drudeParams.x);
force2 += f; force2 += f;
force3 -= f; force3 -= f;
...@@ -52,6 +52,6 @@ u = drudeParams.x*r; ...@@ -52,6 +52,6 @@ u = drudeParams.x*r;
screening = 1-(1+0.5f*u)*EXP(-u); screening = 1-(1+0.5f*u)*EXP(-u);
pairEnergy = drudeParams.y*screening*rInv; pairEnergy = drudeParams.y*screening*rInv;
energy += pairEnergy; energy += pairEnergy;
f = delta*(pairEnergy*rInv*rInv); f = delta*(drudeParams.y*rInv*rInv)*(screening*rInv-0.5f*(1+u)*EXP(-u)*drudeParams.x);
force2 += f; force2 += f;
force4 -= f; force4 -= f;
...@@ -61,7 +61,7 @@ void validateForce(System& system, vector<Vec3>& positions, double expectedEnerg ...@@ -61,7 +61,7 @@ void validateForce(System& system, vector<Vec3>& positions, double expectedEnerg
// Try moving each particle along each axis, and see if the energy changes by the correct amount. // Try moving each particle along each axis, and see if the energy changes by the correct amount.
double offset = 1e-3; double offset = 1e-2;
for (int i = 0; i < system.getNumParticles(); i++) for (int i = 0; i < system.getNumParticles(); i++)
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
vector<Vec3> offsetPos = positions; vector<Vec3> offsetPos = positions;
...@@ -76,9 +76,9 @@ void validateForce(System& system, vector<Vec3>& positions, double expectedEnerg ...@@ -76,9 +76,9 @@ void validateForce(System& system, vector<Vec3>& positions, double expectedEnerg
} }
void testSingleParticle() { void testSingleParticle() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
System system; System system;
system.addParticle(1.0); system.addParticle(1.0);
system.addParticle(1.0); system.addParticle(1.0);
...@@ -92,9 +92,9 @@ void testSingleParticle() { ...@@ -92,9 +92,9 @@ void testSingleParticle() {
} }
void testAnisotropicParticle() { void testAnisotropicParticle() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double a1 = 0.8; const double a1 = 0.8;
const double a2 = 1.1; const double a2 = 1.1;
const double k1 = k/a1; const double k1 = k/a1;
...@@ -124,9 +124,9 @@ double computeScreening(double r, double thole, double alpha1, double alpha2) { ...@@ -124,9 +124,9 @@ double computeScreening(double r, double thole, double alpha1, double alpha2) {
} }
void testThole() { void testThole() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double thole = 2.5; const double thole = 2.5;
System system; System system;
system.addParticle(1.0); system.addParticle(1.0);
...@@ -157,9 +157,9 @@ void testThole() { ...@@ -157,9 +157,9 @@ void testThole() {
} }
void testChangingParameters() { void testChangingParameters() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
Platform& platform = Platform::getPlatformByName("OpenCL"); Platform& platform = Platform::getPlatformByName("OpenCL");
// Create the system. // Create the system.
...@@ -184,9 +184,9 @@ void testChangingParameters() { ...@@ -184,9 +184,9 @@ void testChangingParameters() {
// Modify the parameters. // Modify the parameters.
const double k2 = 2.2; const double k2 = ONE_4PI_EPS0*2.2;
const double charge2 = 0.3; const double charge2 = 0.3;
const double alpha2 = charge2*charge2/k2; const double alpha2 = ONE_4PI_EPS0*charge2*charge2/k2;
drude->setParticleParameters(0, 1, 0, -1, -1, -1, charge2, alpha2, 1, 1); drude->setParticleParameters(0, 1, 0, -1, -1, -1, charge2, alpha2, 1, 1);
drude->updateParametersInContext(context); drude->updateParametersInContext(context);
state = context.getState(State::Energy); state = context.getState(State::Energy);
......
...@@ -53,9 +53,9 @@ extern "C" OPENMM_EXPORT void registerDrudeOpenCLKernelFactories(); ...@@ -53,9 +53,9 @@ extern "C" OPENMM_EXPORT void registerDrudeOpenCLKernelFactories();
void testSinglePair() { void testSinglePair() {
const double temperature = 300.0; const double temperature = 300.0;
const double temperatureDrude = 10.0; const double temperatureDrude = 10.0;
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double mass1 = 1.0; const double mass1 = 1.0;
const double mass2 = 0.1; const double mass2 = 0.1;
const double totalMass = mass1+mass2; const double totalMass = mass1+mass2;
...@@ -132,7 +132,7 @@ void testWater() { ...@@ -132,7 +132,7 @@ void testWater() {
system.addConstraint(startIndex, startIndex+3, 0.09572); system.addConstraint(startIndex, startIndex+3, 0.09572);
system.addConstraint(startIndex+2, startIndex+3, 0.15139); system.addConstraint(startIndex+2, startIndex+3, 0.15139);
system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721)); system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721));
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, 1.71636*1.71636/(100000*4.184), 1, 1); drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184), 1, 1);
} }
vector<Vec3> positions; vector<Vec3> positions;
for (int i = 0; i < gridSize; i++) for (int i = 0; i < gridSize; i++)
......
...@@ -85,7 +85,7 @@ void testWater() { ...@@ -85,7 +85,7 @@ void testWater() {
system.addConstraint(startIndex, startIndex+3, 0.09572); system.addConstraint(startIndex, startIndex+3, 0.09572);
system.addConstraint(startIndex+2, startIndex+3, 0.15139); system.addConstraint(startIndex+2, startIndex+3, 0.15139);
system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721)); system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721));
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, 1.71636*1.71636/(100000*4.184), 1, 1); drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184), 1, 1);
} }
vector<Vec3> positions; vector<Vec3> positions;
for (int i = 0; i < gridSize; i++) for (int i = 0; i < gridSize; i++)
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2011-2013 Stanford University and the Authors. * * Portions copyright (c) 2011-2014 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -136,9 +136,9 @@ double ReferenceCalcDrudeForceKernel::execute(ContextImpl& context, bool include ...@@ -136,9 +136,9 @@ double ReferenceCalcDrudeForceKernel::execute(ContextImpl& context, bool include
RealOpenMM a1 = (p2 == -1 ? 1 : aniso12[i]); RealOpenMM a1 = (p2 == -1 ? 1 : aniso12[i]);
RealOpenMM a2 = (p3 == -1 || p4 == -1 ? 1 : aniso34[i]); RealOpenMM a2 = (p3 == -1 || p4 == -1 ? 1 : aniso34[i]);
RealOpenMM a3 = 3-a1-a2; RealOpenMM a3 = 3-a1-a2;
RealOpenMM k3 = charge[i]*charge[i]/(polarizability[i]*a3); RealOpenMM k3 = ONE_4PI_EPS0*charge[i]*charge[i]/(polarizability[i]*a3);
RealOpenMM k1 = charge[i]*charge[i]/(polarizability[i]*a1) - k3; RealOpenMM k1 = ONE_4PI_EPS0*charge[i]*charge[i]/(polarizability[i]*a1) - k3;
RealOpenMM k2 = charge[i]*charge[i]/(polarizability[i]*a2) - k3; RealOpenMM k2 = ONE_4PI_EPS0*charge[i]*charge[i]/(polarizability[i]*a2) - k3;
// Compute the isotropic force. // Compute the isotropic force.
...@@ -188,6 +188,7 @@ double ReferenceCalcDrudeForceKernel::execute(ContextImpl& context, bool include ...@@ -188,6 +188,7 @@ double ReferenceCalcDrudeForceKernel::execute(ContextImpl& context, bool include
int dipole2 = pair2[i]; int dipole2 = pair2[i];
int dipole1Particles[] = {particle[dipole1], particle1[dipole1]}; int dipole1Particles[] = {particle[dipole1], particle1[dipole1]};
int dipole2Particles[] = {particle[dipole2], particle1[dipole2]}; int dipole2Particles[] = {particle[dipole2], particle1[dipole2]};
RealOpenMM uscale = pairThole[i]/pow(polarizability[dipole1]*polarizability[dipole2], 1.0/6.0);
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++) { for (int k = 0; k < 2; k++) {
int p1 = dipole1Particles[j]; int p1 = dipole1Particles[j];
...@@ -195,10 +196,10 @@ double ReferenceCalcDrudeForceKernel::execute(ContextImpl& context, bool include ...@@ -195,10 +196,10 @@ double ReferenceCalcDrudeForceKernel::execute(ContextImpl& context, bool include
RealOpenMM chargeProduct = charge[dipole1]*charge[dipole2]*(j == k ? 1 : -1); RealOpenMM chargeProduct = charge[dipole1]*charge[dipole2]*(j == k ? 1 : -1);
RealVec delta = pos[p1]-pos[p2]; RealVec delta = pos[p1]-pos[p2];
RealOpenMM r = sqrt(delta.dot(delta)); RealOpenMM r = sqrt(delta.dot(delta));
RealOpenMM u = r*pairThole[i]/pow(polarizability[dipole1]*polarizability[dipole2], 1.0/6.0); RealOpenMM u = r*uscale;
RealOpenMM screening = 1.0 - (1.0+0.5*u)*exp(-u); RealOpenMM screening = 1.0 - (1.0+0.5*u)*exp(-u);
energy += ONE_4PI_EPS0*chargeProduct*screening/r; energy += ONE_4PI_EPS0*chargeProduct*screening/r;
RealVec f = delta*(ONE_4PI_EPS0*chargeProduct*screening/(r*r*r)); RealVec f = delta*(ONE_4PI_EPS0*chargeProduct/(r*r))*(screening/r-0.5*(1+u)*exp(-u)*uscale);
force[p1] += f; force[p1] += f;
force[p2] -= f; force[p2] -= f;
} }
...@@ -461,4 +462,4 @@ void ReferenceIntegrateDrudeSCFStepKernel::minimize(ContextImpl& context, double ...@@ -461,4 +462,4 @@ void ReferenceIntegrateDrudeSCFStepKernel::minimize(ContextImpl& context, double
lbfgsfloatval_t fx; lbfgsfloatval_t fx;
MinimizerData data(context, drudeParticles); MinimizerData data(context, drudeParticles);
lbfgs(numDrudeParticles*3, minimizerPos, &fx, evaluate, NULL, &data, &minimizerParams); lbfgs(numDrudeParticles*3, minimizerPos, &fx, evaluate, NULL, &data, &minimizerParams);
} }
\ No newline at end of file
...@@ -71,14 +71,14 @@ void validateForce(System& system, vector<Vec3>& positions, double expectedEnerg ...@@ -71,14 +71,14 @@ void validateForce(System& system, vector<Vec3>& positions, double expectedEnerg
offsetPos[i][j] = positions[i][j]+offset; offsetPos[i][j] = positions[i][j]+offset;
context.setPositions(offsetPos); context.setPositions(offsetPos);
double e2 = context.getState(State::Energy | State::Forces).getPotentialEnergy(); double e2 = context.getState(State::Energy | State::Forces).getPotentialEnergy();
ASSERT_EQUAL_TOL(state.getForces()[i][j], (e1-e2)/(2*offset), 1e-3); ASSERT_EQUAL_TOL(state.getForces()[i][j], (e1-e2)/(2*offset), 1e-5);
} }
} }
void testSingleParticle() { void testSingleParticle() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
System system; System system;
system.addParticle(1.0); system.addParticle(1.0);
system.addParticle(1.0); system.addParticle(1.0);
...@@ -92,9 +92,9 @@ void testSingleParticle() { ...@@ -92,9 +92,9 @@ void testSingleParticle() {
} }
void testAnisotropicParticle() { void testAnisotropicParticle() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double a1 = 0.8; const double a1 = 0.8;
const double a2 = 1.1; const double a2 = 1.1;
const double k1 = k/a1; const double k1 = k/a1;
...@@ -124,9 +124,9 @@ double computeScreening(double r, double thole, double alpha1, double alpha2) { ...@@ -124,9 +124,9 @@ double computeScreening(double r, double thole, double alpha1, double alpha2) {
} }
void testThole() { void testThole() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double thole = 2.5; const double thole = 2.5;
System system; System system;
system.addParticle(1.0); system.addParticle(1.0);
...@@ -157,9 +157,9 @@ void testThole() { ...@@ -157,9 +157,9 @@ void testThole() {
} }
void testChangingParameters() { void testChangingParameters() {
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
Platform& platform = Platform::getPlatformByName("Reference"); Platform& platform = Platform::getPlatformByName("Reference");
// Create the system. // Create the system.
...@@ -184,9 +184,9 @@ void testChangingParameters() { ...@@ -184,9 +184,9 @@ void testChangingParameters() {
// Modify the parameters. // Modify the parameters.
const double k2 = 2.2; const double k2 = ONE_4PI_EPS0*2.2;
const double charge2 = 0.3; const double charge2 = 0.3;
const double alpha2 = charge2*charge2/k2; const double alpha2 = ONE_4PI_EPS0*charge2*charge2/k2;
drude->setParticleParameters(0, 1, 0, -1, -1, -1, charge2, alpha2, 1, 1); drude->setParticleParameters(0, 1, 0, -1, -1, -1, charge2, alpha2, 1, 1);
drude->updateParametersInContext(context); drude->updateParametersInContext(context);
state = context.getState(State::Energy); state = context.getState(State::Energy);
......
...@@ -53,9 +53,9 @@ extern "C" OPENMM_EXPORT void registerDrudeReferenceKernelFactories(); ...@@ -53,9 +53,9 @@ extern "C" OPENMM_EXPORT void registerDrudeReferenceKernelFactories();
void testSinglePair() { void testSinglePair() {
const double temperature = 300.0; const double temperature = 300.0;
const double temperatureDrude = 10.0; const double temperatureDrude = 10.0;
const double k = 1.5; const double k = ONE_4PI_EPS0*1.5;
const double charge = 0.1; const double charge = 0.1;
const double alpha = charge*charge/k; const double alpha = ONE_4PI_EPS0*charge*charge/k;
const double mass1 = 1.0; const double mass1 = 1.0;
const double mass2 = 0.1; const double mass2 = 0.1;
const double totalMass = mass1+mass2; const double totalMass = mass1+mass2;
...@@ -132,7 +132,7 @@ void testWater() { ...@@ -132,7 +132,7 @@ void testWater() {
system.addConstraint(startIndex, startIndex+3, 0.09572); system.addConstraint(startIndex, startIndex+3, 0.09572);
system.addConstraint(startIndex+2, startIndex+3, 0.15139); system.addConstraint(startIndex+2, startIndex+3, 0.15139);
system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721)); system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721));
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, 1.71636*1.71636/(100000*4.184), 1, 1); drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184), 1, 1);
} }
vector<Vec3> positions; vector<Vec3> positions;
for (int i = 0; i < gridSize; i++) for (int i = 0; i < gridSize; i++)
......
...@@ -85,7 +85,7 @@ void testWater() { ...@@ -85,7 +85,7 @@ void testWater() {
system.addConstraint(startIndex, startIndex+3, 0.09572); system.addConstraint(startIndex, startIndex+3, 0.09572);
system.addConstraint(startIndex+2, startIndex+3, 0.15139); system.addConstraint(startIndex+2, startIndex+3, 0.15139);
system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721)); system.setVirtualSite(startIndex+4, new ThreeParticleAverageSite(startIndex, startIndex+2, startIndex+3, 0.786646558, 0.106676721, 0.106676721));
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, 1.71636*1.71636/(100000*4.184), 1, 1); drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.71636, ONE_4PI_EPS0*1.71636*1.71636/(100000*4.184), 1, 1);
} }
vector<Vec3> positions; vector<Vec3> positions;
for (int i = 0; i < gridSize; i++) for (int i = 0; i < gridSize; i++)
......
...@@ -55,12 +55,16 @@ foreach(SUBDIR ${SUBDIRS}) ...@@ -55,12 +55,16 @@ foreach(SUBDIR ${SUBDIRS})
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.xml" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.xml"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.pdb" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.pdb"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.prmtop" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.prmtop"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.prm"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.inpcrd"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.crd"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.parm7" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.parm7"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.rst7" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.rst7"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.ncrst" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.ncrst"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.dms" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.dms"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.top" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.top"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.par" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.par"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.str"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*psf" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*psf"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/charmm22.*" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/charmm22.*"
) )
......
...@@ -28,7 +28,7 @@ from desmonddmsfile import DesmondDMSFile ...@@ -28,7 +28,7 @@ from desmonddmsfile import DesmondDMSFile
from checkpointreporter import CheckpointReporter from checkpointreporter import CheckpointReporter
from charmmcrdfiles import CharmmCrdFile, CharmmRstFile from charmmcrdfiles import CharmmCrdFile, CharmmRstFile
from charmmparameterset import CharmmParameterSet from charmmparameterset import CharmmParameterSet
from charmmpsffile import CharmmPsfFile from charmmpsffile import CharmmPsfFile, CharmmPSFWarning
# Enumerated values # Enumerated values
......
...@@ -13,7 +13,7 @@ Copyright (c) 2014 the Authors ...@@ -13,7 +13,7 @@ Copyright (c) 2014 the Authors
Author: Jason M. Swails Author: Jason M. Swails
Contributors: Contributors:
Date: April 18, 2014 Date: July 17, 2014
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
...@@ -123,6 +123,8 @@ class CharmmParameterSet(object): ...@@ -123,6 +123,8 @@ class CharmmParameterSet(object):
elif arg.endswith('.str'): elif arg.endswith('.str'):
strs.append(arg) strs.append(arg)
elif arg.endswith('.inp'): elif arg.endswith('.inp'):
# Only consider the file name (since the directory is likely
# "toppar" and will screw up file type detection)
fname = os.path.split(arg)[1] fname = os.path.split(arg)[1]
if 'par' in fname: if 'par' in fname:
pars.append(arg) pars.append(arg)
...@@ -436,11 +438,29 @@ class CharmmParameterSet(object): ...@@ -436,11 +438,29 @@ class CharmmParameterSet(object):
try: try:
at1 = words[0] at1 = words[0]
at2 = words[1] at2 = words[1]
emin = conv(words[2], float, 'NBFIX Emin') emin = abs(conv(words[2], float, 'NBFIX Emin'))
rmin = conv(words[3], float, 'NBFIX Rmin') rmin = conv(words[3], float, 'NBFIX Rmin')
try:
emin14 = abs(conv(words[4], float, 'NBFIX Emin 1-4'))
rmin14 = conv(words[5], float, 'NBFIX Rmin 1-4')
except IndexError:
emin14 = rmin14 = None
try:
self.atom_types_str[at1].add_nbfix(at2, rmin, emin,
rmin14, emin14)
self.atom_types_str[at2].add_nbfix(at1, rmin, emin,
rmin14, emin14)
except KeyError:
# Some stream files define NBFIX terms with an atom that
# is defined in another toppar file that does not
# necessarily have to be loaded. As a result, not every
# NBFIX found here will necessarily need to be applied.
# If we can't find a particular atom type, don't bother
# adding that nbfix and press on
pass
except IndexError: except IndexError:
raise CharmmFileError('Could not parse NBFIX terms.') raise CharmmFileError('Could not parse NBFIX terms.')
self.nbfix_types[(min(at1, at2), max(at1, at2))] = (emin, rmin) self.nbfix_types[(min(at1, at2), max(at1, at2))] = (rmin, emin)
# Now we're done. Load the nonbonded types into the relevant AtomType # Now we're done. Load the nonbonded types into the relevant AtomType
# instances. In order for this to work, all keys in nonbonded_types # instances. In order for this to work, all keys in nonbonded_types
# must be in the self.atom_types_str dict. Raise a RuntimeError if this # must be in the self.atom_types_str dict. Raise a RuntimeError if this
......
...@@ -995,11 +995,25 @@ class CharmmPsfFile(object): ...@@ -995,11 +995,25 @@ class CharmmPsfFile(object):
u.kilojoule_per_mole) u.kilojoule_per_mole)
ene_conv = dihe_frc_conv ene_conv = dihe_frc_conv
# Create the system # Create the system and determine if any of our atoms have NBFIX (and
# therefore requires a CustomNonbondedForce instead)
typenames = set()
system = mm.System() system = mm.System()
if verbose: print('Adding particles...') if verbose: print('Adding particles...')
for atom in self.atom_list: for atom in self.atom_list:
typenames.add(atom.type.name)
system.addParticle(atom.mass) system.addParticle(atom.mass)
has_nbfix_terms = False
typenames = list(typenames)
try:
for i, typename in enumerate(typenames):
typ = params.atom_types_str[typename]
for j in range(i, len(typenames)):
if typenames[j] in typ.nbfix:
has_nbfix_terms = True
raise StopIteration
except StopIteration:
pass
# Set up the constraints # Set up the constraints
if verbose and (constraints is not None and not rigidWater): if verbose and (constraints is not None and not rigidWater):
print('Adding constraints...') print('Adding constraints...')
...@@ -1240,9 +1254,85 @@ class CharmmPsfFile(object): ...@@ -1240,9 +1254,85 @@ class CharmmPsfFile(object):
# Add per-particle nonbonded parameters (LJ params) # Add per-particle nonbonded parameters (LJ params)
sigma_scale = 2**(-1/6) * 2 sigma_scale = 2**(-1/6) * 2
for i, atm in enumerate(self.atom_list): if not has_nbfix_terms:
force.addParticle(atm.charge, sigma_scale*atm.type.rmin*length_conv, for atm in self.atom_list:
abs(atm.type.epsilon*ene_conv)) force.addParticle(atm.charge, sigma_scale*atm.type.rmin*length_conv,
abs(atm.type.epsilon*ene_conv))
else:
for atm in self.atom_list:
force.addParticle(atm.charge, 1.0, 0.0)
# Now add the custom nonbonded force that implements NBFIX. First
# thing we need to do is condense our number of types
lj_idx_list = [0 for atom in self.atom_list]
lj_radii, lj_depths = [], []
num_lj_types = 0
lj_type_list = []
for i, atom in enumerate(self.atom_list):
atom = atom.type
if lj_idx_list[i]: continue # already assigned
num_lj_types += 1
lj_idx_list[i] = num_lj_types
ljtype = (atom.rmin, atom.epsilon)
lj_type_list.append(atom)
lj_radii.append(atom.rmin)
lj_depths.append(atom.epsilon)
for j in range(i+1, len(self.atom_list)):
atom2 = self.atom_list[j].type
if lj_idx_list[j] > 0: continue # already assigned
if atom2 is atom:
lj_idx_list[j] = num_lj_types
elif not atom.nbfix:
# Only non-NBFIXed atom types can be compressed
ljtype2 = (atom2.rmin, atom2.epsilon)
if ljtype == ljtype2:
lj_idx_list[j] = num_lj_types
# Now everything is assigned. Create the A-coefficient and
# B-coefficient arrays
acoef = [0 for i in range(num_lj_types*num_lj_types)]
bcoef = acoef[:]
for i in range(num_lj_types):
for j in range(num_lj_types):
namej = lj_type_list[j].name
try:
rij, wdij, rij14, wdij14 = lj_type_list[i].nbfix[namej]
except KeyError:
rij = (lj_radii[i] + lj_radii[j]) * length_conv
wdij = sqrt(lj_depths[i] * lj_depths[j]) * ene_conv
else:
rij *= length_conv
wdij *= ene_conv
acoef[i+num_lj_types*j] = sqrt(wdij) * rij**6
bcoef[i+num_lj_types*j] = 2 * wdij * rij**6
cforce = mm.CustomNonbondedForce('(a/r6)^2-b/r6; r6=r^6;'
'a=acoef(type1, type2);'
'b=bcoef(type1, type2)')
cforce.addTabulatedFunction('acoef',
mm.Discrete2DFunction(num_lj_types, num_lj_types, acoef))
cforce.addTabulatedFunction('bcoef',
mm.Discrete2DFunction(num_lj_types, num_lj_types, bcoef))
cforce.addPerParticleParameter('type')
cforce.setForceGroup(self.NONBONDED_FORCE_GROUP)
if (nonbondedMethod is ff.PME or nonbondedMethod is ff.Ewald or
nonbondedMethod is ff.CutoffPeriodic):
cforce.setNonbondedMethod(cforce.CutoffPeriodic)
cforce.setCutoffDistance(nonbondedCutoff)
cforce.setUseLongRangeCorrection(True)
elif nonbondedMethod is ff.NoCutoff:
cforce.setNonbondedMethod(cforce.NoCutoff)
elif nonbondedMethod is ff.CutoffNonPeriodic:
cforce.setNonbondedMethod(cforce.CutoffNonPeriodic)
cforce.setCutoffDistance(nonbondedCutoff)
else:
raise ValueError('Unrecognized nonbonded method')
if switchDistance and nonbondedMethod is not ff.NoCutoff:
# make sure it's legal
if switchDistance >= nonbondedCutoff:
raise ValueError('switchDistance is too large compared '
'to the cutoff!')
cforce.setUseSwitchingFunction(True)
cforce.setSwitchingDistance(switchDistance)
for i in lj_idx_list:
cforce.addParticle((i - 1,)) # adjust for indexing from 0
# Add 1-4 interactions # Add 1-4 interactions
excluded_atom_pairs = set() # save these pairs so we don't zero them out excluded_atom_pairs = set() # save these pairs so we don't zero them out
...@@ -1283,6 +1373,13 @@ class CharmmPsfFile(object): ...@@ -1283,6 +1373,13 @@ class CharmmPsfFile(object):
continue continue
force.addException(atom.idx, atom2.idx, 0.0, 0.1, 0.0) force.addException(atom.idx, atom2.idx, 0.0, 0.1, 0.0)
system.addForce(force) system.addForce(force)
# If we needed a CustomNonbondedForce, map all of the exceptions from
# the NonbondedForce to the CustomNonbondedForce
if has_nbfix_terms:
for i in range(force.getNumExceptions()):
ii, jj, q, eps, sig = force.getExceptionParameters(i)
cforce.addExclusion(ii, jj)
system.addForce(cforce)
# Add GB model if we're doing one # Add GB model if we're doing one
if implicitSolvent is not None: if implicitSolvent is not None:
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
<Atom type="swm4ndp-OD" charge="-1.71636" sigma="1" epsilon="0"/> <Atom type="swm4ndp-OD" charge="-1.71636" sigma="1" epsilon="0"/>
</NonbondedForce> </NonbondedForce>
<DrudeForce> <DrudeForce>
<Particle type1="swm4ndp-OD" type2="swm4ndp-O" charge="-1.71636" polarizability="7.040850e-6" thole="1.3"/> <Particle type1="swm4ndp-OD" type2="swm4ndp-O" charge="-1.71636" polarizability="0.000978253" thole="1.3"/>
</DrudeForce> </DrudeForce>
</ForceField> </ForceField>
...@@ -100,7 +100,7 @@ class ForceField(object): ...@@ -100,7 +100,7 @@ class ForceField(object):
"""Load one or more XML files and create a ForceField object based on them. """Load one or more XML files and create a ForceField object based on them.
Parameters: Parameters:
- files A list of XML files defining the force field. Each entry may - files (list) A list of XML files defining the force field. Each entry may
be an absolute file path, a path relative to the current working be an absolute file path, a path relative to the current working
directory, a path relative to this module's data subdirectory directory, a path relative to this module's data subdirectory
(for built in force fields), or an open file-like object with a (for built in force fields), or an open file-like object with a
...@@ -113,47 +113,59 @@ class ForceField(object): ...@@ -113,47 +113,59 @@ class ForceField(object):
self._forces = [] self._forces = []
self._scripts = [] self._scripts = []
for file in files: for file in files:
try: self.loadFile(file)
# this handles either filenames or open file-like objects
tree = etree.parse(file) def loadFile(self, file):
except IOError: """Load an XML file and add the definitions from it to this FieldField.
tree = etree.parse(os.path.join(os.path.dirname(__file__), 'data', file))
root = tree.getroot() Parameters:
- file (string or file) An XML file containing force field definitions. It may
# Load the atom types. be either an absolute file path, a path relative to the current working
directory, a path relative to this module's data subdirectory
if tree.getroot().find('AtomTypes') is not None: (for built in force fields), or an open file-like object with a
for type in tree.getroot().find('AtomTypes').findall('Type'): read() method from which the forcefield XML data can be loaded.
self.registerAtomType(type.attrib) """
try:
# Load the residue templates. # this handles either filenames or open file-like objects
tree = etree.parse(file)
if tree.getroot().find('Residues') is not None: except IOError:
for residue in root.find('Residues').findall('Residue'): tree = etree.parse(os.path.join(os.path.dirname(__file__), 'data', file))
resName = residue.attrib['name'] root = tree.getroot()
template = ForceField._TemplateData(resName)
for atom in residue.findall('Atom'): # Load the atom types.
template.atoms.append(ForceField._TemplateAtomData(atom.attrib['name'], atom.attrib['type'], self._atomTypes[atom.attrib['type']][2]))
for site in residue.findall('VirtualSite'): if tree.getroot().find('AtomTypes') is not None:
template.virtualSites.append(ForceField._VirtualSiteData(site)) for type in tree.getroot().find('AtomTypes').findall('Type'):
for bond in residue.findall('Bond'): self.registerAtomType(type.attrib)
template.addBond(int(bond.attrib['from']), int(bond.attrib['to']))
for bond in residue.findall('ExternalBond'): # Load the residue templates.
b = int(bond.attrib['from'])
template.externalBonds.append(b) if tree.getroot().find('Residues') is not None:
template.atoms[b].externalBonds += 1 for residue in root.find('Residues').findall('Residue'):
self.registerResidueTemplate(template) resName = residue.attrib['name']
template = ForceField._TemplateData(resName)
# Load force definitions for atom in residue.findall('Atom'):
template.atoms.append(ForceField._TemplateAtomData(atom.attrib['name'], atom.attrib['type'], self._atomTypes[atom.attrib['type']][2]))
for child in root: for site in residue.findall('VirtualSite'):
if child.tag in parsers: template.virtualSites.append(ForceField._VirtualSiteData(site))
parsers[child.tag](child, self) for bond in residue.findall('Bond'):
template.addBond(int(bond.attrib['from']), int(bond.attrib['to']))
# Load scripts for bond in residue.findall('ExternalBond'):
b = int(bond.attrib['from'])
for node in tree.getroot().findall('Script'): template.externalBonds.append(b)
self.registerScript(node.text) template.atoms[b].externalBonds += 1
self.registerResidueTemplate(template)
# Load force definitions
for child in root:
if child.tag in parsers:
parsers[child.tag](child, self)
# Load scripts
for node in tree.getroot().findall('Script'):
self.registerScript(node.text)
def getGenerators(self): def getGenerators(self):
"""Get the list of all registered generators.""" """Get the list of all registered generators."""
...@@ -240,6 +252,7 @@ class ForceField(object): ...@@ -240,6 +252,7 @@ class ForceField(object):
def __init__(self): def __init__(self):
self.atomType = {} self.atomType = {}
self.atoms = [] self.atoms = []
self.excludeAtomWith = []
self.virtualSites = {} self.virtualSites = {}
self.bonds = [] self.bonds = []
self.angles = [] self.angles = []
...@@ -302,6 +315,10 @@ class ForceField(object): ...@@ -302,6 +315,10 @@ class ForceField(object):
self.localPos = [float(attrib['p1']), float(attrib['p2']), float(attrib['p3'])] self.localPos = [float(attrib['p1']), float(attrib['p2']), float(attrib['p3'])]
else: else:
raise ValueError('Unknown virtual site type: %s' % self.type) raise ValueError('Unknown virtual site type: %s' % self.type)
if 'excludeWith' in attrib:
self.excludeWith = int(attrib['excludeWith'])
else:
self.excludeWith = self.atoms[0]
def createSystem(self, topology, nonbondedMethod=NoCutoff, nonbondedCutoff=1.0*unit.nanometer, def createSystem(self, topology, nonbondedMethod=NoCutoff, nonbondedCutoff=1.0*unit.nanometer,
constraints=None, rigidWater=True, removeCMMotion=True, hydrogenMass=None, **args): constraints=None, rigidWater=True, removeCMMotion=True, hydrogenMass=None, **args):
...@@ -324,6 +341,8 @@ class ForceField(object): ...@@ -324,6 +341,8 @@ class ForceField(object):
""" """
data = ForceField._SystemData() data = ForceField._SystemData()
data.atoms = list(topology.atoms()) data.atoms = list(topology.atoms())
for atom in data.atoms:
data.excludeAtomWith.append([])
# Make a list of all bonds # Make a list of all bonds
...@@ -363,7 +382,7 @@ class ForceField(object): ...@@ -363,7 +382,7 @@ class ForceField(object):
data.atomType[atom] = template.atoms[match].type data.atomType[atom] = template.atoms[match].type
for site in template.virtualSites: for site in template.virtualSites:
if match == site.index: if match == site.index:
data.virtualSites[atom] = (site, [matchAtoms[i].index for i in site.atoms]) data.virtualSites[atom] = (site, [matchAtoms[i].index for i in site.atoms], matchAtoms[site.excludeWith].index)
# Create the System and add atoms # Create the System and add atoms
...@@ -478,8 +497,9 @@ class ForceField(object): ...@@ -478,8 +497,9 @@ class ForceField(object):
# Add virtual sites # Add virtual sites
for atom in data.virtualSites: for atom in data.virtualSites:
(site, atoms) = data.virtualSites[atom] (site, atoms, excludeWith) = data.virtualSites[atom]
index = atom.index index = atom.index
data.excludeAtomWith[excludeWith].append(index)
if site.type == 'average2': if site.type == 'average2':
sys.setVirtualSite(index, mm.TwoParticleAverageSite(atoms[0], atoms[1], site.weights[0], site.weights[1])) sys.setVirtualSite(index, mm.TwoParticleAverageSite(atoms[0], atoms[1], site.weights[0], site.weights[1]))
elif site.type == 'average3': elif site.type == 'average3':
...@@ -895,7 +915,7 @@ class PeriodicTorsionGenerator: ...@@ -895,7 +915,7 @@ class PeriodicTorsionGenerator:
for (t2, t3, t4) in itertools.permutations(((type2, 1), (type3, 2), (type4, 3))): for (t2, t3, t4) in itertools.permutations(((type2, 1), (type3, 2), (type4, 3))):
if t2[0] in types2 and t3[0] in types3 and t4[0] in types4: if t2[0] in types2 and t3[0] in types3 and t4[0] in types4:
# Workaround to be more consistent with AMBER. It uses wildcards to define most of its # Workaround to be more consistent with AMBER. It uses wildcards to define most of its
# impropers, which leaves the ordering ambigous. It then follows some bizarre rules # impropers, which leaves the ordering ambiguous. It then follows some bizarre rules
# to pick the order. # to pick the order.
a1 = torsion[t2[1]] a1 = torsion[t2[1]]
a2 = torsion[t3[1]] a2 = torsion[t3[1]]
...@@ -991,18 +1011,22 @@ class RBTorsionGenerator: ...@@ -991,18 +1011,22 @@ class RBTorsionGenerator:
if type1 in types1: if type1 in types1:
for (t2, t3, t4) in itertools.permutations(((type2, 1), (type3, 2), (type4, 3))): for (t2, t3, t4) in itertools.permutations(((type2, 1), (type3, 2), (type4, 3))):
if t2[0] in types2 and t3[0] in types3 and t4[0] in types4: if t2[0] in types2 and t3[0] in types3 and t4[0] in types4:
# Workaround to be more consistent with AMBER. It uses wildcards to define most of its if wildcard in (types1, types2, types3, types4):
# impropers, which leaves the ordering ambigous. It then follows some bizarre rules # Workaround to be more consistent with AMBER. It uses wildcards to define most of its
# to pick the order. # impropers, which leaves the ordering ambiguous. It then follows some bizarre rules
a1 = torsion[t2[1]] # to pick the order.
a2 = torsion[t3[1]] a1 = torsion[t2[1]]
e1 = data.atoms[a1].element a2 = torsion[t3[1]]
e2 = data.atoms[a2].element e1 = data.atoms[a1].element
if e1 == e2 and a1 > a2: e2 = data.atoms[a2].element
(a1, a2) = (a2, a1) if e1 == e2 and a1 > a2:
elif e1 != elem.carbon and (e2 == elem.carbon or e1.mass < e2.mass): (a1, a2) = (a2, a1)
(a1, a2) = (a2, a1) elif e1 != elem.carbon and (e2 == elem.carbon or e1.mass < e2.mass):
force.addTorsion(a1, a2, torsion[0], torsion[t4[1]], tordef.c[0], tordef.c[1], tordef.c[2], tordef.c[3], tordef.c[4], tordef.c[5]) (a1, a2) = (a2, a1)
force.addTorsion(a1, a2, torsion[0], torsion[t4[1]], tordef.c[0], tordef.c[1], tordef.c[2], tordef.c[3], tordef.c[4], tordef.c[5])
else:
# There are no wildcards, so the order is unambiguous.
force.addTorsion(torsion[0], torsion[t2[1]], torsion[t3[1]], torsion[t4[1]], tordef.c[0], tordef.c[1], tordef.c[2], tordef.c[3], tordef.c[4], tordef.c[5])
done = True done = True
break break
...@@ -1157,33 +1181,33 @@ class NonbondedGenerator: ...@@ -1157,33 +1181,33 @@ class NonbondedGenerator:
sys.addForce(force) sys.addForce(force)
def postprocessSystem(self, sys, data, args): def postprocessSystem(self, sys, data, args):
# Create exceptions based on bonds, virtual sites, and Drude particles. # Create exceptions based on bonds.
bondIndices = [] bondIndices = []
for bond in data.bonds: for bond in data.bonds:
bondIndices.append((bond.atom1, bond.atom2)) bondIndices.append((bond.atom1, bond.atom2))
# If a virtual site does *not* share exclusions with another atom, add a bond between it and its first parent atom.
for i in range(sys.getNumParticles()): for i in range(sys.getNumParticles()):
if sys.isVirtualSite(i): if sys.isVirtualSite(i):
site = sys.getVirtualSite(i) (site, atoms, excludeWith) = data.virtualSites[data.atoms[i]]
for j in range(site.getNumParticles()): if excludeWith is None:
bondIndices.append((i, site.getParticle(j))) bondIndices.append((i, site.getParticle(0)))
drude = [f for f in sys.getForces() if isinstance(f, mm.DrudeForce)]
if len(drude) > 0: # Certain particles, such as lone pairs and Drude particles, share exclusions with a parent atom.
drude = drude[0] # If the parent atom does not interact with an atom, the child particle does not either.
# For purposes of creating exceptions, a Drude particle is "bonded" to anything
# its parent atom is bonded to. for atom1, atom2 in bondIndices:
drudeMap = {} for child1 in data.excludeAtomWith[atom1]:
for i in range(drude.getNumParticles()): bondIndices.append((child1, atom2))
params = drude.getParticleParameters(i) for child2 in data.excludeAtomWith[atom2]:
drudeMap[params[1]] = params[0] bondIndices.append((child1, child2))
for atom1, atom2 in bondIndices: for child2 in data.excludeAtomWith[atom2]:
drude1 = drudeMap[atom1] if atom1 in drudeMap else None bondIndices.append((atom1, child2))
drude2 = drudeMap[atom2] if atom2 in drudeMap else None
if drude1 is not None: # Create the exceptions.
bondIndices.append((drude1, atom2))
if drude2 is not None:
bondIndices.append((drude1, drude2))
if drude2 is not None:
bondIndices.append((atom1, drude2))
nonbonded = [f for f in sys.getForces() if isinstance(f, mm.NonbondedForce)][0] nonbonded = [f for f in sys.getForces() if isinstance(f, mm.NonbondedForce)][0]
nonbonded.createExceptionsFromBonds(bondIndices, self.coulomb14scale, self.lj14scale) nonbonded.createExceptionsFromBonds(bondIndices, self.coulomb14scale, self.lj14scale)
...@@ -1519,18 +1543,22 @@ class CustomTorsionGenerator: ...@@ -1519,18 +1543,22 @@ class CustomTorsionGenerator:
if type1 in types1: if type1 in types1:
for (t2, t3, t4) in itertools.permutations(((type2, 1), (type3, 2), (type4, 3))): for (t2, t3, t4) in itertools.permutations(((type2, 1), (type3, 2), (type4, 3))):
if t2[0] in types2 and t3[0] in types3 and t4[0] in types4: if t2[0] in types2 and t3[0] in types3 and t4[0] in types4:
# Workaround to be more consistent with AMBER. It uses wildcards to define most of its if wildcard in (types1, types2, types3, types4):
# impropers, which leaves the ordering ambigous. It then follows some bizarre rules # Workaround to be more consistent with AMBER. It uses wildcards to define most of its
# to pick the order. # impropers, which leaves the ordering ambiguous. It then follows some bizarre rules
a1 = torsion[t2[1]] # to pick the order.
a2 = torsion[t3[1]] a1 = torsion[t2[1]]
e1 = data.atoms[a1].element a2 = torsion[t3[1]]
e2 = data.atoms[a2].element e1 = data.atoms[a1].element
if e1 == e2 and a1 > a2: e2 = data.atoms[a2].element
(a1, a2) = (a2, a1) if e1 == e2 and a1 > a2:
elif e1 != elem.carbon and (e2 == elem.carbon or e1.mass < e2.mass): (a1, a2) = (a2, a1)
(a1, a2) = (a2, a1) elif e1 != elem.carbon and (e2 == elem.carbon or e1.mass < e2.mass):
force.addTorsion(a1, a2, torsion[0], torsion[t4[1]], tordef.paramValues) (a1, a2) = (a2, a1)
force.addTorsion(a1, a2, torsion[0], torsion[t4[1]], tordef.paramValues)
else:
# There are no wildcards, so the order is unambiguous.
force.addTorsion(torsion[0], torsion[t2[1]], torsion[t3[1]], torsion[t4[1]], tordef.paramValues)
done = True done = True
break break
...@@ -4290,8 +4318,6 @@ class DrudeGenerator: ...@@ -4290,8 +4318,6 @@ class DrudeGenerator:
# Add Drude particles. # Add Drude particles.
drudeMap = {}
parentMap = {}
for atom in data.atoms: for atom in data.atoms:
t = data.atomType[atom] t = data.atomType[atom]
if t in self.typeMap: if t in self.typeMap:
...@@ -4308,9 +4334,8 @@ class DrudeGenerator: ...@@ -4308,9 +4334,8 @@ class DrudeGenerator:
p[2] = atom2.index p[2] = atom2.index
elif values[3] is not None and type2 in values[3]: elif values[3] is not None and type2 in values[3]:
p[3] = atom2.index p[3] = atom2.index
drudeIndex = force.addParticle(atom.index, p[0], p[1], p[2], p[3], values[4], values[5], values[6], values[7]) force.addParticle(atom.index, p[0], p[1], p[2], p[3], values[4], values[5], values[6], values[7])
drudeMap[atom.index] = p[0] data.excludeAtomWith[p[0]].append(atom.index)
parentMap[p[0]] = (atom.index, drudeIndex)
sys.addForce(force) sys.addForce(force)
def postprocessSystem(self, sys, data, args): def postprocessSystem(self, sys, data, args):
...@@ -4323,14 +4348,14 @@ class DrudeGenerator: ...@@ -4323,14 +4348,14 @@ class DrudeGenerator:
particleMap[drude.getParticleParameters(i)[0]] = i particleMap[drude.getParticleParameters(i)[0]] = i
for i in range(nonbonded.getNumExceptions()): for i in range(nonbonded.getNumExceptions()):
(particle1, particle2, charge, sigma, epsilon) = nonbonded.getExceptionParameters(i) (particle1, particle2, charge, sigma, epsilon) = nonbonded.getExceptionParameters(i)
if charge == 0 and epsilon == 0: if charge._value == 0 and epsilon._value == 0:
# This is an exclusion. # This is an exclusion.
if particle1 in particleMap and particle2 in particleMap: if particle1 in particleMap and particle2 in particleMap:
# It connects two Drude particles, so add a screened pair. # It connects two Drude particles, so add a screened pair.
drude1 = particleMap[particle1] drude1 = particleMap[particle1]
drude2 = particleMap[particle2] drude2 = particleMap[particle2]
type1 = data.atomType[data.atoms[drude1]] type1 = data.atomType[data.atoms[particle1]]
type2 = data.atomType[data.atoms[drude2]] type2 = data.atomType[data.atoms[particle2]]
thole1 = self.typeMap[type1][8] thole1 = self.typeMap[type1][8]
thole2 = self.typeMap[type2][8] thole2 = self.typeMap[type2][8]
drude.addScreenedPair(drude1, drude2, thole1+thole2) drude.addScreenedPair(drude1, drude2, thole1+thole2)
......
...@@ -52,6 +52,7 @@ except: ...@@ -52,6 +52,7 @@ except:
import simtk.unit as units import simtk.unit as units
import simtk.openmm import simtk.openmm
from simtk.openmm.app import element as elem from simtk.openmm.app import element as elem
from simtk.openmm.vec3 import Vec3
import customgbforces as customgb import customgbforces as customgb
#============================================================================================= #=============================================================================================
...@@ -116,6 +117,7 @@ class PrmtopLoader(object): ...@@ -116,6 +117,7 @@ class PrmtopLoader(object):
self._flags=[] self._flags=[]
self._raw_format={} self._raw_format={}
self._raw_data={} self._raw_data={}
self._has_nbfix_terms = False
fIn=open(inFilename) fIn=open(inFilename)
for line in fIn: for line in fIn:
...@@ -218,28 +220,16 @@ class PrmtopLoader(object): ...@@ -218,28 +220,16 @@ class PrmtopLoader(object):
try: try:
return self._massList return self._massList
except AttributeError: except AttributeError:
pass self._massList = [float(x) for x in self._raw_data['MASS']]
return self._massList
self._massList=[]
raw_masses=self._raw_data['MASS']
for ii in range(self.getNumAtoms()):
self._massList.append(float(raw_masses[ii]))
self._massList = self._massList
return self._massList
def getCharges(self): def getCharges(self):
"""Return a list of atomic charges in the system""" """Return a list of atomic charges in the system"""
try: try:
return self._chargeList return self._chargeList
except AttributeError: except AttributeError:
pass self._chargeList = [float(x)/18.2223 for x in self._raw_data['CHARGE']]
return self._chargeList
self._chargeList=[]
raw_charges=self._raw_data['CHARGE']
for ii in range(self.getNumAtoms()):
self._chargeList.append(float(raw_charges[ii])/18.2223)
self._chargeList = self._chargeList
return self._chargeList
def getAtomName(self, iAtom): def getAtomName(self, iAtom):
"""Return the atom name for iAtom""" """Return the atom name for iAtom"""
...@@ -254,11 +244,8 @@ class PrmtopLoader(object): ...@@ -254,11 +244,8 @@ class PrmtopLoader(object):
try: try:
return self._atomTypeIndexes return self._atomTypeIndexes
except AttributeError: except AttributeError:
pass self._atomTypeIndexes = [int(x) for x in self._raw_data['ATOM_TYPE_INDEX']]
self._atomTypeIndexes=[] return self._atomTypeIndexes
for atomTypeIndex in self._raw_data['ATOM_TYPE_INDEX']:
self._atomTypeIndexes.append(int(atomTypeIndex))
return self._atomTypeIndexes
def getAtomType(self, iAtom): def getAtomType(self, iAtom):
"""Return the AMBER atom type for iAtom""" """Return the AMBER atom type for iAtom"""
...@@ -275,11 +262,11 @@ class PrmtopLoader(object): ...@@ -275,11 +262,11 @@ class PrmtopLoader(object):
def getResidueLabel(self, iAtom=None, iRes=None): def getResidueLabel(self, iAtom=None, iRes=None):
"""Return residue label for iAtom OR iRes""" """Return residue label for iAtom OR iRes"""
if iRes==None and iAtom==None: if iRes is None and iAtom is None:
raise Exception("only specify iRes or iAtom, not both") raise Exception("only specify iRes or iAtom, not both")
if iRes!=None and iAtom!=None: if iRes is not None and iAtom is not None:
raise Exception("iRes or iAtom must be set") raise Exception("iRes or iAtom must be set")
if iRes!=None: if iRes is not None:
return self._raw_data['RESIDUE_LABEL'][iRes] return self._raw_data['RESIDUE_LABEL'][iRes]
else: else:
return self.getResidueLabel(iRes=self._getResiduePointer(iAtom)) return self.getResidueLabel(iRes=self._getResiduePointer(iAtom))
...@@ -306,6 +293,9 @@ class PrmtopLoader(object): ...@@ -306,6 +293,9 @@ class PrmtopLoader(object):
elements of the Lennard-Jones A and B coefficient matrices are found, elements of the Lennard-Jones A and B coefficient matrices are found,
NbfixPresent exception is raised NbfixPresent exception is raised
""" """
if self._has_nbfix_terms:
raise NbfixPresent('Off-diagonal Lennard-Jones elements found. '
'Cannot determine LJ parameters for individual atoms.')
try: try:
return self._nonbondTerms return self._nonbondTerms
except AttributeError: except AttributeError:
...@@ -344,13 +334,13 @@ class PrmtopLoader(object): ...@@ -344,13 +334,13 @@ class PrmtopLoader(object):
b = float(self._raw_data['LENNARD_JONES_BCOEF'][index]) b = float(self._raw_data['LENNARD_JONES_BCOEF'][index])
if a == 0 or b == 0: if a == 0 or b == 0:
if a != 0 or b != 0 or (wdij != 0 and rij != 0): if a != 0 or b != 0 or (wdij != 0 and rij != 0):
del self._nonbondTerms self._has_nbfix_terms = True
raise NbfixPresent('Off-diagonal Lennard-Jones elements' raise NbfixPresent('Off-diagonal Lennard-Jones elements'
' found. Cannot determine LJ ' ' found. Cannot determine LJ '
'parameters for individual atoms.') 'parameters for individual atoms.')
elif (abs((a - (wdij * rij ** 12)) / a) > 1e-6 or elif (abs((a - (wdij * rij ** 12)) / a) > 1e-6 or
abs((b - (2 * wdij * rij**6)) / b) > 1e-6): abs((b - (2 * wdij * rij**6)) / b) > 1e-6):
del self._nonbondTerms self._has_nbfix_terms = True
raise NbfixPresent('Off-diagonal Lennard-Jones elements ' raise NbfixPresent('Off-diagonal Lennard-Jones elements '
'found. Cannot determine LJ parameters ' 'found. Cannot determine LJ parameters '
'for individual atoms.') 'for individual atoms.')
...@@ -712,6 +702,10 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode ...@@ -712,6 +702,10 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
warnings.warn("1-4 scaling parameters in topology file are being ignored. " warnings.warn("1-4 scaling parameters in topology file are being ignored. "
"This is not recommended unless you know what you are doing.") "This is not recommended unless you know what you are doing.")
has_1264 = 'LENNARD_JONES_CCOEF' in prmtop._raw_data.keys()
if has_1264:
parm_ccoef = [float(x) for x in prmtop._raw_data['LENNARD_JONES_CCOEF']]
# Use pyopenmm implementation of OpenMM by default. # Use pyopenmm implementation of OpenMM by default.
if mm is None: if mm is None:
mm = simtk.openmm mm = simtk.openmm
...@@ -875,31 +869,52 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode ...@@ -875,31 +869,52 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
idx = nbidx[numTypes*i+j] - 1 idx = nbidx[numTypes*i+j] - 1
acoef[i+numTypes*j] = sqrt(parm_acoef[idx]) * afac acoef[i+numTypes*j] = sqrt(parm_acoef[idx]) * afac
bcoef[i+numTypes*j] = parm_bcoef[idx] * bfac bcoef[i+numTypes*j] = parm_bcoef[idx] * bfac
cforce = mm.CustomNonbondedForce('(a/r6)^2-b/r6; r6=r^6;' if has_1264:
'a=acoef(type1, type2);' cfac = ene_conv * length_conv**4
'b=bcoef(type1, type2);') ccoef = [0 for i in range(numTypes*numTypes)]
for i in range(numTypes):
for j in range(numTypes):
idx = nbidx[numTypes*i+j] - 1
ccoef[i+numTypes*j] = parm_ccoef[idx] * cfac
cforce = mm.CustomNonbondedForce('(a/r6)^2-b/r6-c/r^4; r6=r^6;'
'a=acoef(type1, type2);'
'b=bcoef(type1, type2);'
'c=ccoef(type1, type2);')
else:
cforce = mm.CustomNonbondedForce('(a/r6)^2-b/r6; r6=r^6;'
'a=acoef(type1, type2);'
'b=bcoef(type1, type2);')
cforce.addTabulatedFunction('acoef', cforce.addTabulatedFunction('acoef',
mm.Discrete2DFunction(numTypes, numTypes, acoef)) mm.Discrete2DFunction(numTypes, numTypes, acoef))
cforce.addTabulatedFunction('bcoef', cforce.addTabulatedFunction('bcoef',
mm.Discrete2DFunction(numTypes, numTypes, bcoef)) mm.Discrete2DFunction(numTypes, numTypes, bcoef))
if has_1264:
cforce.addTabulatedFunction('ccoef',
mm.Discrete2DFunction(numTypes, numTypes, ccoef))
cforce.addPerParticleParameter('type') cforce.addPerParticleParameter('type')
for atom in prmtop._getAtomTypeIndexes(): for atom in prmtop._getAtomTypeIndexes():
cforce.addParticle((atom-1,)) cforce.addParticle((atom-1,))
# Now set the various properties based on the NonbondedForce object
if nonbondedMethod in ('PME', 'Ewald', 'CutoffPeriodic'):
cforce.setNonbondedMethod(cforce.CutoffPeriodic)
cforce.setCutoffDistance(nonbondedCutoff)
elif nonbondedMethod == 'CutoffNonPeriodic':
cforce.setNonbondedMethod(cforce.CutoffNonPeriodic)
cforce.setCutoffDistance(nonbondedCutoff)
elif nonbondedMethod == 'NoCutoff':
cforce.setNonbondedMethod(cforce.NoCutoff)
else:
raise ValueError('Unrecognized cutoff option %s' % nonbondedMethod)
else: else:
for (charge, (rVdw, epsilon)) in zip(prmtop.getCharges(), nonbondTerms): for (charge, (rVdw, epsilon)) in zip(prmtop.getCharges(), nonbondTerms):
sigma = rVdw * sigmaScale sigma = rVdw * sigmaScale
force.addParticle(charge, sigma, epsilon) force.addParticle(charge, sigma, epsilon)
if has_1264:
numTypes = prmtop.getNumTypes()
nbidx = [int(x) for x in prmtop._raw_data['NONBONDED_PARM_INDEX']]
ccoef = [0 for i in range(numTypes*numTypes)]
ene_conv = units.kilocalories_per_mole.conversion_factor_to(units.kilojoules_per_mole)
length_conv = units.angstroms.conversion_factor_to(units.nanometers)
cfac = ene_conv * length_conv**4
for i in range(numTypes):
for j in range(numTypes):
idx = nbidx[numTypes*i+j] - 1
ccoef[i+numTypes*j] = parm_ccoef[idx] * cfac
cforce = mm.CustomNonbondedForce('-c/r^4; c=ccoef(type1, type2)')
cforce.addTabulatedFunction('ccoef',
mm.Discrete2DFunction(numTypes, numTypes, ccoef))
cforce.addPerParticleParameter('type')
for atom in prmtop._getAtomTypeIndexes():
cforce.addParticle((atom-1,))
# Add 1-4 Interactions # Add 1-4 Interactions
...@@ -925,10 +940,23 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode ...@@ -925,10 +940,23 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
# Copy the exceptions as exclusions to the CustomNonbondedForce if we have # Copy the exceptions as exclusions to the CustomNonbondedForce if we have
# NBFIX terms # NBFIX terms
if nbfix: if nbfix or has_1264:
for i in range(force.getNumExceptions()): for i in range(force.getNumExceptions()):
ii, jj, chg, sig, eps = force.getExceptionParameters(i) ii, jj, chg, sig, eps = force.getExceptionParameters(i)
cforce.addExclusion(ii, jj) cforce.addExclusion(ii, jj)
# Now set the various properties based on the NonbondedForce object
if nonbondedMethod in ('PME', 'Ewald', 'CutoffPeriodic'):
cforce.setNonbondedMethod(cforce.CutoffPeriodic)
cforce.setCutoffDistance(nonbondedCutoff)
cforce.setUseLongRangeCorrection(True)
elif nonbondedMethod == 'CutoffNonPeriodic':
cforce.setNonbondedMethod(cforce.CutoffNonPeriodic)
cforce.setCutoffDistance(nonbondedCutoff)
elif nonbondedMethod == 'NoCutoff':
cforce.setNonbondedMethod(cforce.NoCutoff)
else:
raise ValueError('Unrecognized cutoff option %s' % nonbondedMethod)
# Add this force to the system
system.addForce(cforce) system.addForce(cforce)
system.addForce(force) system.addForce(force)
...@@ -1190,9 +1218,9 @@ class AmberAsciiRestart(object): ...@@ -1190,9 +1218,9 @@ class AmberAsciiRestart(object):
if hasbox: if hasbox:
boxVectors = np.zeros((3, 3), np.float32) boxVectors = np.zeros((3, 3), np.float32)
else: else:
coordinates = [[0.0, 0.0, 0.0] for i in range(self.natom)] coordinates = [Vec3(0.0, 0.0, 0.0) for i in range(self.natom)]
if hasvels: if hasvels:
velocities = [[0.0, 0.0, 0.0] for i in range(self.natom)] velocities = [Vec3(0.0, 0.0, 0.0) for i in range(self.natom)]
if hasbox: if hasbox:
boxVectors = [[0.0, 0.0, 0.0] for i in range(3)] boxVectors = [[0.0, 0.0, 0.0] for i in range(3)]
...@@ -1202,14 +1230,16 @@ class AmberAsciiRestart(object): ...@@ -1202,14 +1230,16 @@ class AmberAsciiRestart(object):
idx = 0 idx = 0
for i in range(startline, endline): for i in range(startline, endline):
line = lines[i] line = lines[i]
coordinates[idx][0] = float(line[ 0:12]) x = float(line[ 0:12])
coordinates[idx][1] = float(line[12:24]) y = float(line[12:24])
coordinates[idx][2] = float(line[24:36]) z = float(line[24:36])
coordinates[idx] = Vec3(x, y, z)
idx += 1 idx += 1
if idx < self.natom: if idx < self.natom:
coordinates[idx][0] = float(line[36:48]) x = float(line[36:48])
coordinates[idx][1] = float(line[48:60]) y = float(line[48:60])
coordinates[idx][2] = float(line[60:72]) z = float(line[60:72])
coordinates[idx] = Vec3(x, y, z)
idx += 1 idx += 1
self.coordinates = units.Quantity(coordinates, units.angstroms) self.coordinates = units.Quantity(coordinates, units.angstroms)
startline = endline startline = endline
...@@ -1219,14 +1249,16 @@ class AmberAsciiRestart(object): ...@@ -1219,14 +1249,16 @@ class AmberAsciiRestart(object):
idx = 0 idx = 0
for i in range(startline, endline): for i in range(startline, endline):
line = lines[i] line = lines[i]
velocities[idx][0] = float(line[ 0:12]) * VELSCALE x = float(line[ 0:12]) * VELSCALE
velocities[idx][1] = float(line[12:24]) * VELSCALE y = float(line[12:24]) * VELSCALE
velocities[idx][2] = float(line[24:36]) * VELSCALE z = float(line[24:36]) * VELSCALE
velocities[idx] = Vec3(x, y, z)
idx += 1 idx += 1
if idx < self.natom: if idx < self.natom:
velocities[idx][0] = float(line[36:48]) * VELSCALE x = float(line[36:48]) * VELSCALE
velocities[idx][1] = float(line[48:60]) * VELSCALE y = float(line[48:60]) * VELSCALE
velocities[idx][2] = float(line[60:72]) * VELSCALE z = float(line[60:72]) * VELSCALE
velocities[idx] = Vec3(x, y, z)
idx += 1 idx += 1
startline = endline startline = endline
self.velocities = units.Quantity(velocities, self.velocities = units.Quantity(velocities,
...@@ -1241,7 +1273,7 @@ class AmberAsciiRestart(object): ...@@ -1241,7 +1273,7 @@ class AmberAsciiRestart(object):
lengths = tmp[:3] lengths = tmp[:3]
angles = tmp[3:] angles = tmp[3:]
_box_vectors_from_lengths_angles(lengths, angles, boxVectors) _box_vectors_from_lengths_angles(lengths, angles, boxVectors)
self.boxVectors = units.Quantity(boxVectors, units.angstroms) self.boxVectors = [units.Quantity(Vec3(*x), units.angstrom) for x in boxVectors]
class AmberNetcdfRestart(object): class AmberNetcdfRestart(object):
""" """
...@@ -1324,11 +1356,11 @@ class AmberNetcdfRestart(object): ...@@ -1324,11 +1356,11 @@ class AmberNetcdfRestart(object):
# They are already numpy -- convert to list if we don't want numpy # They are already numpy -- convert to list if we don't want numpy
if not asNumpy: if not asNumpy:
self.coordinates = self.coordinates.tolist() self.coordinates = [Vec3(*x) for x in self.coordinates]
if self.velocities is not None: if self.velocities is not None:
self.velocities = self.velocities.tolist() self.velocities = [Vec3(*x) for x in self.velocities]
if self.boxVectors is not None: if self.boxVectors is not None:
self.boxVectors = self.boxVectors.tolist() self.boxVectors = [Vec3(*x) for x in self.boxVectors]
# Now add the units # Now add the units
self.coordinates = units.Quantity(self.coordinates, units.angstroms) self.coordinates = units.Quantity(self.coordinates, units.angstroms)
...@@ -1336,7 +1368,7 @@ class AmberNetcdfRestart(object): ...@@ -1336,7 +1368,7 @@ class AmberNetcdfRestart(object):
self.velocities = units.Quantity(self.velocities, self.velocities = units.Quantity(self.velocities,
units.angstroms/units.picoseconds) units.angstroms/units.picoseconds)
if self.boxVectors is not None: if self.boxVectors is not None:
self.boxVectors = units.Quantity(self.boxVectors, units.angstroms) self.boxVectors = [units.Quantity(x, units.angstroms) for x in self.boxVectors]
self.time = units.Quantity(self.time, units.picosecond) self.time = units.Quantity(self.time, units.picosecond)
def _box_vectors_from_lengths_angles(lengths, angles, boxVectors): def _box_vectors_from_lengths_angles(lengths, angles, boxVectors):
...@@ -1426,6 +1458,7 @@ def readAmberCoordinates(filename, asNumpy=False): ...@@ -1426,6 +1458,7 @@ def readAmberCoordinates(filename, asNumpy=False):
try: try:
crdfile = AmberAsciiRestart(filename) crdfile = AmberAsciiRestart(filename)
except TypeError: except TypeError:
raise
raise TypeError('Problem parsing %s as an ASCII Amber restart file' raise TypeError('Problem parsing %s as an ASCII Amber restart file'
% filename) % filename)
except (IndexError, ValueError): except (IndexError, ValueError):
......
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