Commit bceea302 authored by Peter Eastman's avatar Peter Eastman
Browse files

Merge remote-tracking branch 'origin/master' into qc

parents 2e6397b7 a1b2641c
...@@ -524,6 +524,47 @@ void testReordering() { ...@@ -524,6 +524,47 @@ void testReordering() {
} }
} }
/**
* Test a System where multiple virtual sites are all calculated from the same particles.
*/
void testOverlappingSites() {
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
NonbondedForce* nonbonded = new NonbondedForce();
system.addForce(nonbonded);
nonbonded->addParticle(1.0, 0.0, 0.0);
nonbonded->addParticle(-0.5, 0.0, 0.0);
nonbonded->addParticle(-0.5, 0.0, 0.0);
vector<Vec3> positions;
positions.push_back(Vec3(0, 0, 0));
positions.push_back(Vec3(10, 0, 0));
positions.push_back(Vec3(0, 10, 0));
for (int i = 0; i < 20; i++) {
system.addParticle(0.0);
double u = 0.1*((i+1)%4);
double v = 0.05*i;
system.setVirtualSite(3+i, new ThreeParticleAverageSite(0, 1, 2, u, v, 1-u-v));
nonbonded->addParticle(i%2 == 0 ? -1.0 : 1.0, 0.0, 0.0);
positions.push_back(Vec3());
}
VerletIntegrator i1(0.002);
VerletIntegrator i2(0.002);
Context c1(system, i1, Platform::getPlatformByName("Reference"));
Context c2(system, i2, platform);
c1.setPositions(positions);
c2.setPositions(positions);
c1.applyConstraints(0.0001);
c2.applyConstraints(0.0001);
State s1 = c1.getState(State::Positions | State::Forces);
State s2 = c2.getState(State::Positions | State::Forces);
for (int i = 0; i < system.getNumParticles(); i++)
ASSERT_EQUAL_VEC(s1.getPositions()[i], s2.getPositions()[i], 1e-5);
for (int i = 0; i < 3; i++)
ASSERT_EQUAL_VEC(s1.getForces()[i], s2.getForces()[i], 1e-5);
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
try { try {
if (argc > 1) if (argc > 1)
...@@ -535,6 +576,7 @@ int main(int argc, char* argv[]) { ...@@ -535,6 +576,7 @@ int main(int argc, char* argv[]) {
testLocalCoordinates(); testLocalCoordinates();
testConservationLaws(); testConservationLaws();
testReordering(); testReordering();
testOverlappingSites();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -126,13 +126,15 @@ public: ...@@ -126,13 +126,15 @@ public:
* Set the torsion-torsion grid at the specified index * Set the torsion-torsion grid at the specified index
* *
* @param index the index of the torsion-torsion for which to get parameters * @param index the index of the torsion-torsion for which to get parameters
* @param grid grid * @param grid either 3 or 6 values may be specified per grid point. If the derivatives
* are omitted, they are calculated automatically by fitting a 2D spline to
* the energies.
* grid[x][y][0] = x value * grid[x][y][0] = x value
* grid[x][y][1] = y value * grid[x][y][1] = y value
* grid[x][y][2] = function value * grid[x][y][2] = energy
* grid[x][y][3] = dfdx value * grid[x][y][3] = dEdx value
* grid[x][y][4] = dfdy value * grid[x][y][4] = dEdy value
* grid[x][y][5] = dfd(xy) value * grid[x][y][5] = dEd(xy) value
*/ */
void setTorsionTorsionGrid(int index, const std::vector<std::vector<std::vector<double> > >& grid); void setTorsionTorsionGrid(int index, const std::vector<std::vector<std::vector<double> > >& grid);
...@@ -181,29 +183,7 @@ public: ...@@ -181,29 +183,7 @@ public:
_spacing[0] = _spacing[1] = 1.0; _spacing[0] = _spacing[1] = 1.0;
} }
TorsionTorsionGridInfo(const TorsionTorsionGrid& grid) { TorsionTorsionGridInfo(const TorsionTorsionGrid& grid);
_grid.resize(grid.size());
for(unsigned int kk = 0; kk < grid.size(); kk++){
_grid[kk].resize(grid[kk].size());
for(unsigned int jj = 0; jj < grid[kk].size(); jj++){
_grid[kk][jj].resize(grid[kk][jj].size());
for(unsigned int ii = 0; ii < grid[kk][jj].size(); ii++){
_grid[kk][jj][ii] = grid[kk][jj][ii];
}
}
}
_startValues[0] = _grid[0][0][0];
_startValues[1] = _grid[0][0][1];
_spacing[0] = static_cast<double>(_grid.size()-1)/360.0;
_spacing[1] = static_cast<double>(grid.size()-1)/360.0;
_size[0] = static_cast<int>(grid.size());
_size[1] = static_cast<int>(grid[0].size());
}
const TorsionTorsionGrid& getTorsionTorsionGrid(void) const { const TorsionTorsionGrid& getTorsionTorsionGrid(void) const {
return _grid; return _grid;
......
...@@ -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) 2008-2009 Stanford University and the Authors. * * Portions copyright (c) 2008-2014 Stanford University and the Authors. *
* Authors: * * Authors: *
* Contributors: * * Contributors: *
* * * *
...@@ -33,8 +33,10 @@ ...@@ -33,8 +33,10 @@
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
#include "openmm/AmoebaTorsionTorsionForce.h" #include "openmm/AmoebaTorsionTorsionForce.h"
#include "openmm/internal/AmoebaTorsionTorsionForceImpl.h" #include "openmm/internal/AmoebaTorsionTorsionForceImpl.h"
#include "openmm/internal/SplineFitter.h"
using namespace OpenMM; using namespace OpenMM;
using namespace std;
AmoebaTorsionTorsionForce::AmoebaTorsionTorsionForce() { AmoebaTorsionTorsionForce::AmoebaTorsionTorsionForce() {
} }
...@@ -82,3 +84,102 @@ void AmoebaTorsionTorsionForce::setTorsionTorsionGrid(int index, const TorsionTo ...@@ -82,3 +84,102 @@ void AmoebaTorsionTorsionForce::setTorsionTorsionGrid(int index, const TorsionTo
ForceImpl* AmoebaTorsionTorsionForce::createImpl() const { ForceImpl* AmoebaTorsionTorsionForce::createImpl() const {
return new AmoebaTorsionTorsionForceImpl(*this); return new AmoebaTorsionTorsionForceImpl(*this);
} }
AmoebaTorsionTorsionForce::TorsionTorsionGridInfo::TorsionTorsionGridInfo(const TorsionTorsionGrid& grid) {
if (grid[0][0][0] != grid[1][0][0])
_grid = grid;
else {
// We need to transpose the grid.
int xsize = grid[0].size();
int ysize = grid.size();
_grid.resize(xsize);
for (int i = 0; i < xsize; i++) {
_grid[i].resize(ysize);
for (int j = 0; j < ysize; j++)
_grid[i][j] = grid[j][i];
}
}
_startValues[0] = _grid[0][0][0];
_startValues[1] = _grid[0][0][1];
_spacing[0] = static_cast<double>(_grid.size()-1)/360.0;
_spacing[1] = static_cast<double>(_grid.size()-1)/360.0;
_size[0] = static_cast<int>(_grid.size());
_size[1] = static_cast<int>(_grid[0].size());
if (_grid[0][0].size() == 3) {
// We need to compute the derivatives ourselves. First determine if the grid is periodic.
int xsize = _size[0];
int ysize = _size[1];
bool periodic = true;
for (int i = 0; i < xsize; i++)
if (_grid[i][0][2] != _grid[i][ysize-1][2])
periodic = false;
for (int i = 0; i < ysize; i++)
if (_grid[0][i][2] != _grid[xsize-1][i][2])
periodic = false;
// Compute derivatives with respect to the first angle.
vector<double> x(xsize), y(ysize);
for (int i = 0; i < xsize; i++)
x[i] = _grid[i][0][0];
for (int i = 0; i < ysize; i++)
y[i] = _grid[0][i][1];
vector<double> d1(xsize*ysize), d2(xsize*ysize), d12(xsize*ysize);
vector<double> t(xsize), deriv(xsize);
for (int i = 0; i < ysize; i++) {
for (int j = 0; j < xsize; j++)
t[j] = _grid[j][i][2];
if (periodic)
SplineFitter::createPeriodicSpline(x, t, deriv);
else
SplineFitter::createNaturalSpline(x, t, deriv);
for (int j = 0; j < xsize; j++)
d1[j+xsize*i] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[j]);
}
// Compute derivatives with respect to the second angle.
t.resize(ysize);
deriv.resize(ysize);
for (int i = 0; i < xsize; i++) {
for (int j = 0; j < ysize; j++)
t[j] = _grid[i][j][2];
if (periodic)
SplineFitter::createPeriodicSpline(y, t, deriv);
else
SplineFitter::createNaturalSpline(y, t, deriv);
for (int j = 0; j < ysize; j++)
d2[i+xsize*j] = SplineFitter::evaluateSplineDerivative(y, t, deriv, y[j]);
}
// Compute cross derivatives.
t.resize(xsize);
deriv.resize(xsize);
for (int i = 0; i < ysize; i++) {
for (int j = 0; j < xsize; j++)
t[j] = d2[j+xsize*i];
if (periodic)
SplineFitter::createPeriodicSpline(x, t, deriv);
else
SplineFitter::createNaturalSpline(x, t, deriv);
for (int j = 0; j < xsize; j++)
d12[j+xsize*i] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[j]);
}
// Add the derivatives to the grid.
for (int i = 0; i < xsize; i++)
for (int j = 0; j < ysize; j++) {
_grid[i][j].push_back(d1[i+xsize*j]);
_grid[i][j].push_back(d2[i+xsize*j]);
_grid[i][j].push_back(d12[i+xsize*j]);
}
}
}
...@@ -49,7 +49,7 @@ extern "C" OPENMM_EXPORT void registerAmoebaReferenceKernelFactories(); ...@@ -49,7 +49,7 @@ extern "C" OPENMM_EXPORT void registerAmoebaReferenceKernelFactories();
const double TOL = 1e-4; const double TOL = 1e-4;
TorsionTorsionGrid& getTorsionGrid( int gridIndex ) { TorsionTorsionGrid getTorsionGrid(int gridIndex, bool includeDerivs) {
static double grid[4][625][6] = { static double grid[4][625][6] = {
{ {
...@@ -2557,35 +2557,32 @@ static double grid[4][625][6] = { ...@@ -2557,35 +2557,32 @@ static double grid[4][625][6] = {
{ 165.0000, 180.0000, -0.182999000E+01, 0.377952854E-01, 0.233583295E-01, -0.109828932E-02 }, { 165.0000, 180.0000, -0.182999000E+01, 0.377952854E-01, 0.233583295E-01, -0.109828932E-02 },
{ 180.0000, 180.0000, -0.146854000E+01, 0.491175487E-02, 0.195601580E-02, -0.163177030E-02 } } }; { 180.0000, 180.0000, -0.146854000E+01, 0.491175487E-02, 0.195601580E-02, -0.163177030E-02 } } };
// static std::vector< std::vector< std::vector<double> > > TorsionTorsionGrid int elementCount = (includeDerivs ? 6 : 3);
static std::vector<TorsionTorsionGrid> grids; std::vector<TorsionTorsionGrid> grids(4);
if( grids.size() == 0 ){ for( int ii = 0; ii < 4; ii++ ){
grids.resize(4); grids[ii].resize( 25 );
for( int ii = 0; ii < 4; ii++ ){ for( int jj = 0; jj < 25; jj++ ){
grids[ii].resize( 25 ); grids[ii][jj].resize(25);
for( int jj = 0; jj < 25; jj++ ){ for( int kk = 0; kk < 25; kk++ ){
grids[ii][jj].resize(25); grids[ii][jj][kk].resize(elementCount);
for( int kk = 0; kk < 25; kk++ ){
grids[ii][jj][kk].resize(6);
}
} }
int index = 0; }
for( int jj = 0; jj < 25; jj++ ){ int index = 0;
for( int kk = 0; kk < 25; kk++ ){ for( int jj = 0; jj < 25; jj++ ){
int jjIndex = static_cast<int>(((grid[ii][index][0] + 180.0)/15.0)+1.0e-05); for( int kk = 0; kk < 25; kk++ ){
int kkIndex = static_cast<int>(((grid[ii][index][1] + 180.0)/15.0)+1.0e-05); int jjIndex = static_cast<int>(((grid[ii][index][0] + 180.0)/15.0)+1.0e-05);
for( int ll = 0; ll < 6; ll++ ){ int kkIndex = static_cast<int>(((grid[ii][index][1] + 180.0)/15.0)+1.0e-05);
grids[ii][kk][jj][ll] = grid[ii][index][ll]; for( int ll = 0; ll < elementCount; ll++ ){
} grids[ii][kk][jj][ll] = grid[ii][index][ll];
index++;
} }
index++;
} }
} }
} }
return grids[gridIndex]; return grids[gridIndex];
} }
void testTorsionTorsion( FILE* log, int systemId ) { void testTorsionTorsion(int systemId, bool includeDerivs) {
System system; System system;
int numberOfParticles = 6; int numberOfParticles = 6;
...@@ -2645,11 +2642,11 @@ void testTorsionTorsion( FILE* log, int systemId ) { ...@@ -2645,11 +2642,11 @@ void testTorsionTorsion( FILE* log, int systemId ) {
expectedEnergy = -3.372536909E+00; expectedEnergy = -3.372536909E+00;
} }
amoebaTorsionTorsionForce->addTorsionTorsion( 0, 1, 2, 3, 4, chiralCheckAtomIndex, 0 ); amoebaTorsionTorsionForce->addTorsionTorsion(0, 1, 2, 3, 4, chiralCheckAtomIndex, 0);
amoebaTorsionTorsionForce->setTorsionTorsionGrid( 0, getTorsionGrid( gridIndex ) ); amoebaTorsionTorsionForce->setTorsionTorsionGrid(0, getTorsionGrid(gridIndex, includeDerivs));
system.addForce(amoebaTorsionTorsionForce); system.addForce(amoebaTorsionTorsionForce);
Context context(system, integrator, Platform::getPlatformByName( "Reference")); Context context(system, integrator, Platform::getPlatformByName("Reference"));
context.setPositions(positions); context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy); State state = context.getState(State::Forces | State::Energy);
...@@ -2662,18 +2659,6 @@ void testTorsionTorsion( FILE* log, int systemId ) { ...@@ -2662,18 +2659,6 @@ void testTorsionTorsion( FILE* log, int systemId ) {
forces[ii][2] *= conversion; forces[ii][2] *= conversion;
} }
#ifdef AMOEBA_DEBUG
if( log ){
(void) fprintf( log, "computeAmoebaTorsionTorsionForces: expected energy=%14.7e %14.7e\n", expectedEnergy, state.getPotentialEnergy() );
for( unsigned int ii = 0; ii < forces.size(); ii++ ){
(void) fprintf( log, "%6u [%14.7e %14.7e %14.7e] [%14.7e %14.7e %14.7e]\n", ii,
expectedForces[ii][0], expectedForces[ii][1], expectedForces[ii][2],
forces[ii][0], forces[ii][1], forces[ii][2] );
}
(void) fflush( log );
}
#endif
double tolerance = 1.0e-03; double tolerance = 1.0e-03;
for( unsigned int ii = 0; ii < forces.size(); ii++ ){ for( unsigned int ii = 0; ii < forces.size(); ii++ ){
ASSERT_EQUAL_VEC( expectedForces[ii], forces[ii], tolerance ); ASSERT_EQUAL_VEC( expectedForces[ii], forces[ii], tolerance );
...@@ -2687,10 +2672,8 @@ int main( int numberOfArguments, char* argv[] ) { ...@@ -2687,10 +2672,8 @@ int main( int numberOfArguments, char* argv[] ) {
try { try {
std::cout << "TestReferenceAmoebaTorsionTorsionForce running test..." << std::endl; std::cout << "TestReferenceAmoebaTorsionTorsionForce running test..." << std::endl;
registerAmoebaReferenceKernelFactories(); registerAmoebaReferenceKernelFactories();
//registerAmoebaCudaKernelFactories(); testTorsionTorsion(1, true);
testTorsionTorsion(1, false);
FILE* log = NULL;
testTorsionTorsion( log, 1 );
} catch(const std::exception& e) { } catch(const std::exception& e) {
std::cout << "exception: " << e.what() << std::endl; std::cout << "exception: " << e.what() << std::endl;
std::cout << "FAIL - ERROR. Test failed." << std::endl; std::cout << "FAIL - ERROR. Test failed." << std::endl;
......
...@@ -33,8 +33,8 @@ ...@@ -33,8 +33,8 @@
#include "openmm/Context.h" #include "openmm/Context.h"
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "openmm/internal/OSRngSeed.h"
#include "openmm/DrudeKernels.h" #include "openmm/DrudeKernels.h"
#include <cmath>
#include <ctime> #include <ctime>
#include <string> #include <string>
...@@ -49,7 +49,7 @@ DrudeLangevinIntegrator::DrudeLangevinIntegrator(double temperature, double fric ...@@ -49,7 +49,7 @@ DrudeLangevinIntegrator::DrudeLangevinIntegrator(double temperature, double fric
setDrudeFriction(drudeFrictionCoeff); setDrudeFriction(drudeFrictionCoeff);
setStepSize(stepSize); setStepSize(stepSize);
setConstraintTolerance(1e-5); setConstraintTolerance(1e-5);
setRandomNumberSeed((int) time(NULL)); setRandomNumberSeed(osrngseed());
} }
void DrudeLangevinIntegrator::initialize(ContextImpl& contextRef) { void DrudeLangevinIntegrator::initialize(ContextImpl& contextRef) {
......
...@@ -33,10 +33,10 @@ ...@@ -33,10 +33,10 @@
#include "openmm/Context.h" #include "openmm/Context.h"
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "openmm/internal/OSRngSeed.h"
#include "openmm/RpmdKernels.h" #include "openmm/RpmdKernels.h"
#include "SimTKOpenMMRealType.h" #include "SimTKOpenMMRealType.h"
#include <cmath> #include <cmath>
#include <ctime>
#include <string> #include <string>
using namespace OpenMM; using namespace OpenMM;
...@@ -48,7 +48,7 @@ RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictio ...@@ -48,7 +48,7 @@ RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictio
setFriction(frictionCoeff); setFriction(frictionCoeff);
setStepSize(stepSize); setStepSize(stepSize);
setConstraintTolerance(1e-5); setConstraintTolerance(1e-5);
setRandomNumberSeed((int) time(NULL)); setRandomNumberSeed(osrngseed());
} }
RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictionCoeff, double stepSize) : RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictionCoeff, double stepSize) :
...@@ -57,7 +57,7 @@ RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictio ...@@ -57,7 +57,7 @@ RPMDIntegrator::RPMDIntegrator(int numCopies, double temperature, double frictio
setFriction(frictionCoeff); setFriction(frictionCoeff);
setStepSize(stepSize); setStepSize(stepSize);
setConstraintTolerance(1e-5); setConstraintTolerance(1e-5);
setRandomNumberSeed((int) time(NULL)); setRandomNumberSeed(osrngseed());
} }
void RPMDIntegrator::initialize(ContextImpl& contextRef) { void RPMDIntegrator::initialize(ContextImpl& contextRef) {
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h" #include "openmm/internal/AssertionUtilities.h"
#include "openmm/CustomNonbondedForce.h"
#include "openmm/NonbondedForce.h" #include "openmm/NonbondedForce.h"
#include "openmm/OpenMMException.h" #include "openmm/OpenMMException.h"
#include <iostream> #include <iostream>
...@@ -166,10 +167,62 @@ void testReplaceExceptions() { ...@@ -166,10 +167,62 @@ void testReplaceExceptions() {
ASSERT(charge == 5.0); ASSERT(charge == 5.0);
} }
/**
* This is the same as testFindExceptions(), except it tests adding exclusions to a CustomNonbondedForce.
*/
void testFindCustomExclusions() {
CustomNonbondedForce nonbonded("r");
vector<pair<int, int> > bonds;
vector<double> params;
for (int i = 0; i < NUM_ATOMS; i++)
nonbonded.addParticle(params);
// loop over all main-chain atoms (even numbered atoms)
for (int i = 0; i < NUM_ATOMS-1; i += 2)
{
// side-chain bonds
bonds.push_back(pair<int, int>(i, i+1));
// main-chain bonds
if (i < NUM_ATOMS-2) // penultimate atom (NUM_ATOMS-2) has no subsequent main-chain atom
bonds.push_back(pair<int, int>(i, i+2));
}
nonbonded.createExclusionsFromBonds(bonds, 3);
// Build lists of the expected exclusions.
vector<set<int> > expectedExclusions(NUM_ATOMS);
int totalExclusions = 0;
for (int i = 0; i < NUM_ATOMS; i += 2) {
addAtomsToExclusions(i, i+1, expectedExclusions, totalExclusions);
addAtomsToExclusions(i, i+2, expectedExclusions, totalExclusions);
addAtomsToExclusions(i, i+3, expectedExclusions, totalExclusions);
addAtomsToExclusions(i, i+4, expectedExclusions, totalExclusions);
addAtomsToExclusions(i+1, i+2, expectedExclusions, totalExclusions);
addAtomsToExclusions(i, i+5, expectedExclusions, totalExclusions);
addAtomsToExclusions(i, i+6, expectedExclusions, totalExclusions);
addAtomsToExclusions(i+1, i+3, expectedExclusions, totalExclusions);
addAtomsToExclusions(i+1, i+4, expectedExclusions, totalExclusions);
}
for (int i = 0; i < nonbonded.getNumExclusions(); i++) {
int particle1, particle2;
nonbonded.getExclusionParticles(i, particle1, particle2);
}
// Compare them to the exceptions that were generated.
ASSERT_EQUAL(totalExclusions, nonbonded.getNumExclusions());
for (int i = 0; i < nonbonded.getNumExclusions(); i++) {
int particle1, particle2;
nonbonded.getExclusionParticles(i, particle1, particle2);
ASSERT(expectedExclusions[particle1].find(particle2) != expectedExclusions[particle1].end());
}
}
int main() { int main() {
try { try {
testFindExceptions(); testFindExceptions();
testReplaceExceptions(); testReplaceExceptions();
testFindCustomExclusions();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -55,8 +55,12 @@ foreach(SUBDIR ${SUBDIRS}) ...@@ -55,8 +55,12 @@ 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}/*.parm7"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.rst7"
"${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}/*psf" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*psf"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/charmm22.*" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/charmm22.*"
) )
......
...@@ -6,9 +6,9 @@ Simbios, the NIH National Center for Physics-Based Simulation of ...@@ -6,9 +6,9 @@ Simbios, the NIH National Center for Physics-Based Simulation of
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) 2012 Stanford University and the Authors. Portions copyright (c) 2012-2014 Stanford University and the Authors.
Authors: Peter Eastman Authors: Peter Eastman
Contributors: Contributors: Jason Swails
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"),
...@@ -31,87 +31,97 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. ...@@ -31,87 +31,97 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
__author__ = "Peter Eastman" __author__ = "Peter Eastman"
__version__ = "1.0" __version__ = "1.0"
from functools import wraps
from simtk.openmm.app.internal import amber_file_parser from simtk.openmm.app.internal import amber_file_parser
from simtk.unit import Quantity, nanometers, picoseconds from simtk.unit import Quantity, nanometers, picoseconds
import warnings
try: try:
import numpy import numpy as np
except: except:
pass np = None
def numpy_protector(func):
"""
Decorator to emit useful error messages if users try to request numpy
processing if numpy is not available. Raises ImportError if numpy could not
be found
"""
@wraps(func)
def wrapper(self, asNumpy=False):
if asNumpy and np is None:
raise ImportError('Could not import numpy. Cannot set asNumpy=True')
return func(self, asNumpy=asNumpy)
return wrapper
class AmberInpcrdFile(object): class AmberInpcrdFile(object):
"""AmberInpcrdFile parses an AMBER inpcrd file and loads the data stored in it.""" """AmberInpcrdFile parses an AMBER inpcrd file and loads the data stored in it."""
def __init__(self, file, loadVelocities=False, loadBoxVectors=False): def __init__(self, file, loadVelocities=None, loadBoxVectors=None):
"""Load an inpcrd file. """Load an inpcrd file.
An inpcrd file contains atom positions and, optionally, velocities and periodic box dimensions. An inpcrd file contains atom positions and, optionally, velocities and periodic box dimensions.
Unfortunately, it is sometimes impossible to determine from the file itself exactly what data
it contains. You therefore must specify in advance what data to load. It is stored into this
object's "positions", "velocities", and "boxVectors" fields.
Parameters: Parameters:
- file (string) the name of the file to load - file (string) the name of the file to load
- loadVelocities (boolean=False) whether to load velocities from the file - loadVelocities (boolean=None) deprecated. Velocities are loaded automatically if present
- loadBoxVectors (boolean=False) whether to load the periodic box vectors - loadBoxVectors (boolean=None) deprecated. Box vectors are loaded automatically if present
""" """
results = amber_file_parser.readAmberCoordinates(file, read_velocities=loadVelocities, read_box=loadBoxVectors) self.file = file
if loadVelocities: if loadVelocities is not None or loadBoxVectors is not None:
## The atom positions read from the inpcrd file warnings.warn('loadVelocities and loadBoxVectors have been '
self.positions = results[0] 'deprecated. velocities and box information '
if loadBoxVectors: 'is loaded automatically if the inpcrd file contains '
## The periodic box vectors read from the inpcrd file 'them.', DeprecationWarning)
self.boxVectors = results[1] results = amber_file_parser.readAmberCoordinates(file)
## The atom velocities read from the inpcrd file self.positions, self.velocities, self.boxVectors = results
self.velocities = results[2] # Cached numpy arrays
else:
self.velocities = results[1]
elif loadBoxVectors:
self.positions = results[0]
self.boxVectors = results[1]
else:
self.positions = results
self._numpyPositions = None self._numpyPositions = None
if loadVelocities: self._numpyVelocities = None
self._numpyVelocities = None self._numpyBoxVectors = None
if loadBoxVectors:
self._numpyBoxVectors = None
@numpy_protector
def getPositions(self, asNumpy=False): def getPositions(self, asNumpy=False):
"""Get the atomic positions. """Get the atomic positions.
Parameters: Parameters:
- asNumpy (boolean=False) if true, the values are returned as a numpy array instead of a list of Vec3s - asNumpy (boolean=False) if true, the values are returned as a numpy array instead of a list of Vec3s
""" """
if asNumpy: if asNumpy:
if self._numpyPositions is None: if self._numpyPositions is None:
self._numpyPositions = Quantity(numpy.array(self.positions.value_in_unit(nanometers)), nanometers) self._numpyPositions = Quantity(np.array(self.positions.value_in_unit(nanometers)), nanometers)
return self._numpyPositions return self._numpyPositions
return self.positions return self.positions
@numpy_protector
def getVelocities(self, asNumpy=False): def getVelocities(self, asNumpy=False):
"""Get the atomic velocities. """Get the atomic velocities.
Parameters: Parameters:
- asNumpy (boolean=False) if true, the vectors are returned as numpy arrays instead of Vec3s - asNumpy (boolean=False) if true, the vectors are returned as numpy arrays instead of Vec3s
""" """
if self.velocities is None:
raise AttributeError('velocities not found in %s' % self.file)
if asNumpy: if asNumpy:
if self._numpyVelocities is None: if self._numpyVelocities is None:
self._numpyVelocities = Quantity(numpy.array(self.velocities.value_in_unit(nanometers/picoseconds)), nanometers/picoseconds) self._numpyVelocities = Quantity(np.array(self.velocities.value_in_unit(nanometers/picoseconds)), nanometers/picoseconds)
return self._numpyVelocities return self._numpyVelocities
return self.velocities return self.velocities
@numpy_protector
def getBoxVectors(self, asNumpy=False): def getBoxVectors(self, asNumpy=False):
"""Get the periodic box vectors. """Get the periodic box vectors.
Parameters: Parameters:
- asNumpy (boolean=False) if true, the values are returned as a numpy array instead of a list of Vec3s - asNumpy (boolean=False) if true, the values are returned as a numpy array instead of a list of Vec3s
""" """
if self.boxVectors is None:
raise AttributeError('Box information not found in %s' % self.file)
if asNumpy: if asNumpy:
if self._numpyBoxVectors is None: if self._numpyBoxVectors is None:
self._numpyBoxVectors = [] self._numpyBoxVectors = []
self._numpyBoxVectors.append(Quantity(numpy.array(self.boxVectors[0].value_in_unit(nanometers)), nanometers)) self._numpyBoxVectors.append(Quantity(np.array(self.boxVectors[0].value_in_unit(nanometers)), nanometers))
self._numpyBoxVectors.append(Quantity(numpy.array(self.boxVectors[1].value_in_unit(nanometers)), nanometers)) self._numpyBoxVectors.append(Quantity(np.array(self.boxVectors[1].value_in_unit(nanometers)), nanometers))
self._numpyBoxVectors.append(Quantity(numpy.array(self.boxVectors[2].value_in_unit(nanometers)), nanometers)) self._numpyBoxVectors.append(Quantity(np.array(self.boxVectors[2].value_in_unit(nanometers)), nanometers))
return self._numpyBoxVectors return self._numpyBoxVectors
return self.boxVectors return self.boxVectors
...@@ -13,7 +13,7 @@ Copyright (c) 2014 the Authors ...@@ -13,7 +13,7 @@ Copyright (c) 2014 the Authors
Author: Jason Deckman Author: Jason Deckman
Contributors: Jason M. Swails Contributors: Jason M. Swails
Date: April 19, 2014 Date: June 6, 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"),
...@@ -105,7 +105,7 @@ class CharmmCrdFile(object): ...@@ -105,7 +105,7 @@ class CharmmCrdFile(object):
self.resname.append(line[2]) self.resname.append(line[2])
self.attype.append(line[3]) self.attype.append(line[3])
pos = Vec3(float(line[4]), float(line[5]), float(line[6])) pos = Vec3(float(line[4]), float(line[5]), float(line[6]))
self.positions.append(pos * u.angstroms) self.positions.append(pos)
self.segid.append(line[7]) self.segid.append(line[7])
self.resid.append(int(line[8])) self.resid.append(int(line[8]))
self.weighting.append(float(line[9])) self.weighting.append(float(line[9]))
...@@ -120,6 +120,10 @@ class CharmmCrdFile(object): ...@@ -120,6 +120,10 @@ class CharmmCrdFile(object):
except (ValueError, IndexError), e: except (ValueError, IndexError), e:
raise CharmmFileError('Error parsing CHARMM coordinate file') raise CharmmFileError('Error parsing CHARMM coordinate file')
# Apply units to the positions now. Do it this way to allow for
# (possible) numpy functionality in the future.
self.positions = u.Quantity(self.positions, u.angstroms)
class CharmmRstFile(object): class CharmmRstFile(object):
""" """
Reads and parses data, velocities and coordinates from a CHARMM restart Reads and parses data, velocities and coordinates from a CHARMM restart
...@@ -209,8 +213,9 @@ class CharmmRstFile(object): ...@@ -209,8 +213,9 @@ class CharmmRstFile(object):
self.velocities = [v * ONE_TIMESCALE for v in self.velocities] self.velocities = [v * ONE_TIMESCALE for v in self.velocities]
# Add units to positions and velocities # Add units to positions and velocities
self.positions *= u.angstroms self.positions = u.Quantity(self.positions, u.angstroms)
self.velocities *= u.angstroms / u.picoseconds self.positionsold = u.Quantity(self.positionsold, u.angstroms)
self.velocities = u.Quantity(self.velocities, u.angstroms/u.picoseconds)
def _scan(self, handle, str, r=0): # read lines in file until str is found def _scan(self, handle, str, r=0): # read lines in file until str is found
scanning = True scanning = True
......
...@@ -241,6 +241,10 @@ class CharmmParameterSet(object): ...@@ -241,6 +241,10 @@ class CharmmParameterSet(object):
if line.startswith('HBOND'): if line.startswith('HBOND'):
section = None section = None
continue continue
# It seems like files? sections? can be terminated with 'END'
if line.startswith('END'): # should this be case-insensitive?
section = None
continue
# If we have no section, skip # If we have no section, skip
if section is None: continue if section is None: continue
# Now handle each section specifically # Now handle each section specifically
......
...@@ -90,6 +90,7 @@ class CharmmPsfFile(object): ...@@ -90,6 +90,7 @@ class CharmmPsfFile(object):
- bond_list - bond_list
- angle_list - angle_list
- dihedral_list - dihedral_list
- dihedral_parameter_list
- improper_list - improper_list
- cmap_list - cmap_list
- donor_list # hbonds donors? - donor_list # hbonds donors?
...@@ -349,6 +350,7 @@ class CharmmPsfFile(object): ...@@ -349,6 +350,7 @@ class CharmmPsfFile(object):
self.bond_list = bond_list self.bond_list = bond_list
self.angle_list = angle_list self.angle_list = angle_list
self.dihedral_list = dihedral_list self.dihedral_list = dihedral_list
self.dihedral_parameter_list = TrackedList()
self.improper_list = improper_list self.improper_list = improper_list
self.cmap_list = cmap_list self.cmap_list = cmap_list
self.donor_list = donor_list self.donor_list = donor_list
...@@ -599,9 +601,9 @@ class CharmmPsfFile(object): ...@@ -599,9 +601,9 @@ class CharmmPsfFile(object):
central atoms in impropers) and see if that matches. Wild-cards central atoms in impropers) and see if that matches. Wild-cards
will apply ONLY if specific parameters cannot be found. will apply ONLY if specific parameters cannot be found.
- This method will expand the dihedral_list attribute by adding a - This method will expand the dihedral_parameter_list attribute by
separate Dihedral object for each term for types that have a adding a separate Dihedral object for each term for types that
multi-term expansion have a multi-term expansion
""" """
# First load the atom types # First load the atom types
types_are_int = False types_are_int = False
...@@ -643,12 +645,9 @@ class CharmmPsfFile(object): ...@@ -643,12 +645,9 @@ class CharmmPsfFile(object):
self.urey_bradley_list.append(ub) self.urey_bradley_list.append(ub)
except KeyError: except KeyError:
raise MissingParameter('Missing angle type for %r' % ang) raise MissingParameter('Missing angle type for %r' % ang)
# Next load all of the dihedrals. This is a little trickier since we # Next load all of the dihedrals.
# need to back up the existing dihedral list and replace it with a self.dihedral_parameter_list = TrackedList()
# longer one that has only one Fourier term per Dihedral instance. for dih in self.dihedral_list:
dihedral_list = self.dihedral_list
self.dihedral_list = TrackedList()
for dih in dihedral_list:
# Store the atoms # Store the atoms
a1, a2, a3, a4 = dih.atom1, dih.atom2, dih.atom3, dih.atom4 a1, a2, a3, a4 = dih.atom1, dih.atom2, dih.atom3, dih.atom4
at1, at2, at3, at4 = a1.attype, a2.attype, a3.attype, a4.attype at1, at2, at3, at4 = a1.attype, a2.attype, a3.attype, a4.attype
...@@ -662,14 +661,14 @@ class CharmmPsfFile(object): ...@@ -662,14 +661,14 @@ class CharmmPsfFile(object):
'%r' % dih) '%r' % dih)
dtlist = parmset.dihedral_types[key] dtlist = parmset.dihedral_types[key]
for i, dt in enumerate(dtlist): for i, dt in enumerate(dtlist):
self.dihedral_list.append(Dihedral(a1, a2, a3, a4, dt)) self.dihedral_parameter_list.append(Dihedral(a1,a2,a3,a4,dt))
# See if we include the end-group interactions for this # See if we include the end-group interactions for this
# dihedral. We do IFF it is the last or only dihedral term and # dihedral. We do IFF it is the last or only dihedral term and
# it is NOT in the angle/bond partners # it is NOT in the angle/bond partners
if i != len(dtlist) - 1: if i != len(dtlist) - 1:
self.dihedral_list[-1].end_groups_active = False self.dihedral_parameter_list[-1].end_groups_active = False
elif a1 in a4.bond_partners or a1 in a4.angle_partners: elif a1 in a4.bond_partners or a1 in a4.angle_partners:
self.dihedral_list[-1].end_groups_active = False self.dihedral_parameter_list[-1].end_groups_active = False
# Now do the impropers # Now do the impropers
for imp in self.improper_list: for imp in self.improper_list:
# Store the atoms # Store the atoms
...@@ -755,6 +754,12 @@ class CharmmPsfFile(object): ...@@ -755,6 +754,12 @@ class CharmmPsfFile(object):
- alpha, beta, gamma (floats, optional) : Angles between the - alpha, beta, gamma (floats, optional) : Angles between the
periodic cells. periodic cells.
""" """
try:
# Since we are setting the box, delete the cached box lengths if we
# have them to make sure they are recomputed if desired.
del self._boxLengths
except AttributeError:
pass
self.box_vectors = _box_vectors_from_lengths_angles(a, b, c, self.box_vectors = _box_vectors_from_lengths_angles(a, b, c,
alpha, beta, gamma) alpha, beta, gamma)
# If we already have a _topology instance, then we have possibly changed # If we already have a _topology instance, then we have possibly changed
...@@ -952,8 +957,6 @@ class CharmmPsfFile(object): ...@@ -952,8 +957,6 @@ class CharmmPsfFile(object):
- flexibleConstraints (bool=True) Are our constraints flexible or not? - flexibleConstraints (bool=True) Are our constraints flexible or not?
- verbose (bool=False) Optionally prints out a running progress report - verbose (bool=False) Optionally prints out a running progress report
""" """
# back up the dihedral list
dihedral_list = self.dihedral_list
# Load the parameter set # Load the parameter set
self.loadParameters(params.condense()) self.loadParameters(params.condense())
hasbox = self.topology.getUnitCellDimensions() is not None hasbox = self.topology.getUnitCellDimensions() is not None
...@@ -1103,7 +1106,7 @@ class CharmmPsfFile(object): ...@@ -1103,7 +1106,7 @@ class CharmmPsfFile(object):
if verbose: print('Adding torsions...') if verbose: print('Adding torsions...')
force = mm.PeriodicTorsionForce() force = mm.PeriodicTorsionForce()
force.setForceGroup(self.DIHEDRAL_FORCE_GROUP) force.setForceGroup(self.DIHEDRAL_FORCE_GROUP)
for tor in self.dihedral_list: for tor in self.dihedral_parameter_list:
force.addTorsion(tor.atom1.idx, tor.atom2.idx, tor.atom3.idx, force.addTorsion(tor.atom1.idx, tor.atom2.idx, tor.atom3.idx,
tor.atom4.idx, tor.dihedral_type.per, tor.atom4.idx, tor.dihedral_type.per,
tor.dihedral_type.phase*pi/180, tor.dihedral_type.phase*pi/180,
...@@ -1235,7 +1238,7 @@ class CharmmPsfFile(object): ...@@ -1235,7 +1238,7 @@ class CharmmPsfFile(object):
# 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
sigma_scale = 2**(-1/6) sigma_scale = 2**(-1/6)
for tor in self.dihedral_list: for tor in self.dihedral_parameter_list:
# First check to see if atoms 1 and 4 are already excluded because # First check to see if atoms 1 and 4 are already excluded because
# they are 1-2 or 1-3 pairs (would happen in 6-member rings or # they are 1-2 or 1-3 pairs (would happen in 6-member rings or
# fewer). Then check that they're not already added as exclusions # fewer). Then check that they're not already added as exclusions
...@@ -1355,9 +1358,6 @@ class CharmmPsfFile(object): ...@@ -1355,9 +1358,6 @@ class CharmmPsfFile(object):
# Cache our system for easy access # Cache our system for easy access
self._system = system self._system = system
# Restore the dihedral list to allow reparametrization later
self.dihedral_list = dihedral_list
return system return system
@property @property
...@@ -1422,9 +1422,30 @@ class CharmmPsfFile(object): ...@@ -1422,9 +1422,30 @@ class CharmmPsfFile(object):
@property @property
def boxLengths(self): def boxLengths(self):
""" Return tuple of 3 units """ """ Return tuple of 3 units """
try:
# See if we have a cached version
return self._boxLengths
except AttributeError:
pass
if self.box_vectors is not None: if self.box_vectors is not None:
return (self.box_vectors[0][0], self.box_vectors[0][1], # Get the lengths of each vector
self.box_vectors[0][2]) if u.is_quantity(self.box_vectors):
# Unlikely -- each vector is like a quantity
vecs = self.box_vectors.value_in_unit(u.nanometers)
elif u.is_quantity(self.box_vectors[0]):
# Assume all box vectors are quantities
vecs = [x.value_in_unit(u.nanometers) for x in self.box_vectors]
else:
# Assume nanometers
vecs = self.box_vectors
a = sqrt(vecs[0][0]*vecs[0][0] + vecs[0][1]*vecs[0][1] +
vecs[0][2]*vecs[0][2])
b = sqrt(vecs[1][0]*vecs[1][0] + vecs[1][1]*vecs[1][1] +
vecs[1][2]*vecs[1][2])
c = sqrt(vecs[2][0]*vecs[2][0] + vecs[2][1]*vecs[2][1] +
vecs[2][2]*vecs[2][2])
self._boxLengths = (a, b, c) * u.nanometers
return self._boxLengths
return None return None
@boxLengths.setter @boxLengths.setter
...@@ -1440,6 +1461,12 @@ class CharmmPsfFile(object): ...@@ -1440,6 +1461,12 @@ class CharmmPsfFile(object):
@boxVectors.setter @boxVectors.setter
def boxVectors(self, stuff): def boxVectors(self, stuff):
""" Sets the box vectors """ """ Sets the box vectors """
try:
# We may be changing the box, so delete the cached box lengths to
# make sure they are recomputed if desired
del self._boxLengths
except AttributeError:
pass
self.box_vectors = stuff self.box_vectors = stuff
def deleteCmap(self): def deleteCmap(self):
......
This source diff could not be displayed because it is too large. You can view the blob instead.
<ForceField>
<Info>
<Source>amoebapro13_5-2014.prm</Source>
<DateGenerated>2014-05-08</DateGenerated>
<Reference>Yue Shi, Zhen Xia, Jiajing Zhang, Robert Best, Chuanjie Wu, Jay W. Ponder, and Pengyu Ren. Polarizable Atomic Multipole-Based AMOEBA Force Field for Proteins. Journal of Chemical Theory and Computation, 9(9):4046–4063, 2013.</Reference>
</Info>
<AmoebaGeneralizedKirkwoodForce solventDielectric="78.3" soluteDielectric="1.0" includeCavityTerm="1" probeRadius="0.14" surfaceAreaFactor="-170.351730663">
<GeneralizedKirkwood type="1" charge="-0.22483" shct="0.79" />
<GeneralizedKirkwood type="2" charge="-0.09722" shct="0.72" />
<GeneralizedKirkwood type="2" charge="-0.31113" shct="0.72" />
<GeneralizedKirkwood type="2" charge="-0.18217" shct="0.72" />
<GeneralizedKirkwood type="2" charge="-0.06142" shct="0.72" />
<GeneralizedKirkwood type="3" charge="0.79586" shct="0.72" />
<GeneralizedKirkwood type="4" charge="0.13964" shct="0.85" />
<GeneralizedKirkwood type="5" charge="-0.76219" shct="0.85" />
<GeneralizedKirkwood type="6" charge="0.07437" shct="0.85" />
<GeneralizedKirkwood type="7" charge="-0.15418" shct="0.79" />
<GeneralizedKirkwood type="7" charge="-0.14115" shct="0.79" />
<GeneralizedKirkwood type="8" charge="-0.17302" shct="0.72" />
<GeneralizedKirkwood type="8" charge="-0.36199" shct="0.72" />
<GeneralizedKirkwood type="8" charge="-0.11441" shct="0.72" />
<GeneralizedKirkwood type="8" charge="0.04440" shct="0.72" />
<GeneralizedKirkwood type="9" charge="0.81010" shct="0.72" />
<GeneralizedKirkwood type="9" charge="0.85003" shct="0.72" />
<GeneralizedKirkwood type="10" charge="0.12044" shct="0.85" />
<GeneralizedKirkwood type="10" charge="0.12637" shct="0.85" />
<GeneralizedKirkwood type="11" charge="-0.75149" shct="0.85" />
<GeneralizedKirkwood type="11" charge="-0.77014" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.08514" shct="0.85" />
<GeneralizedKirkwood type="12" charge="0.07834" shct="0.85" />
<GeneralizedKirkwood type="13" charge="-0.15959" shct="0.72" />
<GeneralizedKirkwood type="14" charge="0.07420" shct="0.85" />
<GeneralizedKirkwood type="15" charge="-0.06548" shct="0.72" />
<GeneralizedKirkwood type="16" charge="0.07117" shct="0.85" />
<GeneralizedKirkwood type="17" charge="-0.16832" shct="0.72" />
<GeneralizedKirkwood type="18" charge="0.06566" shct="0.85" />
<GeneralizedKirkwood type="19" charge="-0.13173" shct="0.72" />
<GeneralizedKirkwood type="20" charge="0.06916" shct="0.85" />
<GeneralizedKirkwood type="21" charge="-0.02887" shct="0.72" />
<GeneralizedKirkwood type="22" charge="0.08767" shct="0.85" />
<GeneralizedKirkwood type="23" charge="-0.17741" shct="0.72" />
<GeneralizedKirkwood type="24" charge="0.05874" shct="0.85" />
<GeneralizedKirkwood type="25" charge="-0.08555" shct="0.72" />
<GeneralizedKirkwood type="26" charge="0.08230" shct="0.85" />
<GeneralizedKirkwood type="27" charge="-0.11939" shct="0.72" />
<GeneralizedKirkwood type="28" charge="0.07096" shct="0.85" />
<GeneralizedKirkwood type="29" charge="-0.17217" shct="0.72" />
<GeneralizedKirkwood type="30" charge="0.06823" shct="0.85" />
<GeneralizedKirkwood type="31" charge="-0.16882" shct="0.72" />
<GeneralizedKirkwood type="32" charge="0.06001" shct="0.85" />
<GeneralizedKirkwood type="33" charge="0.16229" shct="0.72" />
<GeneralizedKirkwood type="34" charge="0.05600" shct="0.85" />
<GeneralizedKirkwood type="35" charge="-0.44145" shct="0.85" />
<GeneralizedKirkwood type="36" charge="0.23017" shct="0.85" />
<GeneralizedKirkwood type="37" charge="0.10834" shct="0.72" />
<GeneralizedKirkwood type="38" charge="0.06805" shct="0.85" />
<GeneralizedKirkwood type="39" charge="-0.40177" shct="0.85" />
<GeneralizedKirkwood type="40" charge="0.24568" shct="0.85" />
<GeneralizedKirkwood type="41" charge="-0.16081" shct="0.72" />
<GeneralizedKirkwood type="42" charge="0.06784" shct="0.85" />
<GeneralizedKirkwood type="43" charge="-0.30144" shct="0.72" />
<GeneralizedKirkwood type="43" charge="-0.30144" shct="0.72" />
<GeneralizedKirkwood type="43" charge="-0.08027" shct="0.72" />
<GeneralizedKirkwood type="44" charge="0.14381" shct="0.85" />
<GeneralizedKirkwood type="44" charge="0.00975" shct="0.85" />
<GeneralizedKirkwood type="45" charge="-0.03264" shct="0.96" />
<GeneralizedKirkwood type="46" charge="0.10947" shct="0.85" />
<GeneralizedKirkwood type="47" charge="0.07683" shct="0.96" />
<GeneralizedKirkwood type="48" charge="-0.23113" shct="0.72" />
<GeneralizedKirkwood type="49" charge="-0.85155" shct="0.96" />
<GeneralizedKirkwood type="50" charge="-0.13558" shct="0.79" />
<GeneralizedKirkwood type="51" charge="-0.26070" shct="0.72" />
<GeneralizedKirkwood type="52" charge="0.90470" shct="0.72" />
<GeneralizedKirkwood type="53" charge="-0.76984" shct="0.85" />
<GeneralizedKirkwood type="54" charge="0.09550" shct="0.85" />
<GeneralizedKirkwood type="55" charge="-0.13205" shct="0.72" />
<GeneralizedKirkwood type="55" charge="-0.12680" shct="0.72" />
<GeneralizedKirkwood type="56" charge="0.09686" shct="0.85" />
<GeneralizedKirkwood type="56" charge="0.11510" shct="0.85" />
<GeneralizedKirkwood type="57" charge="-0.16591" shct="0.72" />
<GeneralizedKirkwood type="57" charge="-0.14420" shct="0.72" />
<GeneralizedKirkwood type="58" charge="0.08886" shct="0.85" />
<GeneralizedKirkwood type="58" charge="0.12121" shct="0.85" />
<GeneralizedKirkwood type="59" charge="-0.03932" shct="0.72" />
<GeneralizedKirkwood type="60" charge="0.06588" shct="0.85" />
<GeneralizedKirkwood type="61" charge="-0.11216" shct="0.72" />
<GeneralizedKirkwood type="62" charge="0.09205" shct="0.85" />
<GeneralizedKirkwood type="63" charge="-0.04246" shct="0.72" />
<GeneralizedKirkwood type="64" charge="0.04681" shct="0.72" />
<GeneralizedKirkwood type="65" charge="0.00023" shct="0.85" />
<GeneralizedKirkwood type="66" charge="-0.02656" shct="0.72" />
<GeneralizedKirkwood type="67" charge="0.00719" shct="0.85" />
<GeneralizedKirkwood type="68" charge="-0.02866" shct="0.72" />
<GeneralizedKirkwood type="69" charge="0.00685" shct="0.85" />
<GeneralizedKirkwood type="70" charge="-0.10731" shct="0.72" />
<GeneralizedKirkwood type="71" charge="0.09011" shct="0.85" />
<GeneralizedKirkwood type="72" charge="-0.05309" shct="0.72" />
<GeneralizedKirkwood type="73" charge="0.07134" shct="0.72" />
<GeneralizedKirkwood type="74" charge="0.00345" shct="0.85" />
<GeneralizedKirkwood type="75" charge="-0.12512" shct="0.72" />
<GeneralizedKirkwood type="76" charge="0.01090" shct="0.85" />
<GeneralizedKirkwood type="77" charge="0.35744" shct="0.72" />
<GeneralizedKirkwood type="78" charge="-0.46438" shct="0.85" />
<GeneralizedKirkwood type="79" charge="0.22899" shct="0.85" />
<GeneralizedKirkwood type="80" charge="-0.14909" shct="0.72" />
<GeneralizedKirkwood type="81" charge="0.07954" shct="0.85" />
<GeneralizedKirkwood type="82" charge="-0.21590" shct="0.72" />
<GeneralizedKirkwood type="83" charge="-0.04549" shct="0.72" />
<GeneralizedKirkwood type="84" charge="0.01759" shct="0.85" />
<GeneralizedKirkwood type="85" charge="-0.15892" shct="0.72" />
<GeneralizedKirkwood type="86" charge="-0.03324" shct="0.85" />
<GeneralizedKirkwood type="87" charge="0.62054" shct="0.72" />
<GeneralizedKirkwood type="88" charge="-0.91150" shct="0.85" />
<GeneralizedKirkwood type="89" charge="-0.16339" shct="0.72" />
<GeneralizedKirkwood type="90" charge="0.08819" shct="0.85" />
<GeneralizedKirkwood type="91" charge="-0.14846" shct="0.72" />
<GeneralizedKirkwood type="92" charge="0.09676" shct="0.72" />
<GeneralizedKirkwood type="93" charge="0.02989" shct="0.85" />
<GeneralizedKirkwood type="94" charge="0.00548" shct="0.72" />
<GeneralizedKirkwood type="95" charge="-0.03588" shct="0.79" />
<GeneralizedKirkwood type="96" charge="0.08805" shct="0.85" />
<GeneralizedKirkwood type="97" charge="0.27382" shct="0.72" />
<GeneralizedKirkwood type="98" charge="-0.20979" shct="0.72" />
<GeneralizedKirkwood type="99" charge="0.00102" shct="0.85" />
<GeneralizedKirkwood type="100" charge="-0.11296" shct="0.72" />
<GeneralizedKirkwood type="101" charge="0.00446" shct="0.85" />
<GeneralizedKirkwood type="102" charge="0.06902" shct="0.72" />
<GeneralizedKirkwood type="103" charge="0.00474" shct="0.85" />
<GeneralizedKirkwood type="104" charge="-0.01987" shct="0.72" />
<GeneralizedKirkwood type="105" charge="0.00374" shct="0.85" />
<GeneralizedKirkwood type="106" charge="-0.10044" shct="0.72" />
<GeneralizedKirkwood type="107" charge="0.11241" shct="0.85" />
<GeneralizedKirkwood type="108" charge="0.16205" shct="0.72" />
<GeneralizedKirkwood type="109" charge="-0.10600" shct="0.79" />
<GeneralizedKirkwood type="110" charge="0.20247" shct="0.85" />
<GeneralizedKirkwood type="111" charge="0.04476" shct="0.72" />
<GeneralizedKirkwood type="112" charge="0.08897" shct="0.85" />
<GeneralizedKirkwood type="113" charge="0.39335" shct="0.72" />
<GeneralizedKirkwood type="114" charge="0.09278" shct="0.85" />
<GeneralizedKirkwood type="115" charge="-0.08186" shct="0.79" />
<GeneralizedKirkwood type="116" charge="0.14211" shct="0.85" />
<GeneralizedKirkwood type="117" charge="-0.10846" shct="0.72" />
<GeneralizedKirkwood type="118" charge="0.08849" shct="0.85" />
<GeneralizedKirkwood type="119" charge="0.04660" shct="0.72" />
<GeneralizedKirkwood type="120" charge="-0.16996" shct="0.79" />
<GeneralizedKirkwood type="121" charge="0.13110" shct="0.85" />
<GeneralizedKirkwood type="122" charge="0.08866" shct="0.72" />
<GeneralizedKirkwood type="123" charge="0.02049" shct="0.85" />
<GeneralizedKirkwood type="124" charge="0.34991" shct="0.72" />
<GeneralizedKirkwood type="125" charge="0.03404" shct="0.85" />
<GeneralizedKirkwood type="126" charge="-0.50635" shct="0.79" />
<GeneralizedKirkwood type="127" charge="-0.11338" shct="0.72" />
<GeneralizedKirkwood type="128" charge="0.08990" shct="0.85" />
<GeneralizedKirkwood type="129" charge="0.20611" shct="0.72" />
<GeneralizedKirkwood type="130" charge="-0.56975" shct="0.79" />
<GeneralizedKirkwood type="131" charge="-0.02289" shct="0.72" />
<GeneralizedKirkwood type="132" charge="0.03876" shct="0.85" />
<GeneralizedKirkwood type="133" charge="0.33110" shct="0.72" />
<GeneralizedKirkwood type="134" charge="0.03651" shct="0.85" />
<GeneralizedKirkwood type="135" charge="-0.13121" shct="0.79" />
<GeneralizedKirkwood type="136" charge="0.10796" shct="0.85" />
<GeneralizedKirkwood type="137" charge="-0.33682" shct="0.72" />
<GeneralizedKirkwood type="138" charge="0.04965" shct="0.85" />
<GeneralizedKirkwood type="139" charge="1.01811" shct="0.72" />
<GeneralizedKirkwood type="140" charge="-0.85879" shct="0.85" />
<GeneralizedKirkwood type="141" charge="-0.17303" shct="0.72" />
<GeneralizedKirkwood type="142" charge="0.10446" shct="0.85" />
<GeneralizedKirkwood type="143" charge="0.85923" shct="0.72" />
<GeneralizedKirkwood type="144" charge="-0.63514" shct="0.85" />
<GeneralizedKirkwood type="145" charge="-0.43939" shct="0.85" />
<GeneralizedKirkwood type="146" charge="0.24242" shct="0.85" />
<GeneralizedKirkwood type="147" charge="-0.15914" shct="0.72" />
<GeneralizedKirkwood type="148" charge="0.10149" shct="0.85" />
<GeneralizedKirkwood type="149" charge="0.76984" shct="0.72" />
<GeneralizedKirkwood type="150" charge="-0.74313" shct="0.85" />
<GeneralizedKirkwood type="151" charge="-0.28938" shct="0.79" />
<GeneralizedKirkwood type="152" charge="0.14092" shct="0.85" />
<GeneralizedKirkwood type="153" charge="-0.10324" shct="0.72" />
<GeneralizedKirkwood type="154" charge="0.06492" shct="0.85" />
<GeneralizedKirkwood type="155" charge="-0.35416" shct="0.72" />
<GeneralizedKirkwood type="156" charge="0.06420" shct="0.85" />
<GeneralizedKirkwood type="157" charge="1.05691" shct="0.72" />
<GeneralizedKirkwood type="158" charge="-0.89737" shct="0.85" />
<GeneralizedKirkwood type="159" charge="-0.10668" shct="0.72" />
<GeneralizedKirkwood type="160" charge="0.09513" shct="0.85" />
<GeneralizedKirkwood type="161" charge="-0.23637" shct="0.72" />
<GeneralizedKirkwood type="162" charge="0.10600" shct="0.85" />
<GeneralizedKirkwood type="163" charge="0.90086" shct="0.72" />
<GeneralizedKirkwood type="164" charge="-0.60677" shct="0.85" />
<GeneralizedKirkwood type="165" charge="-0.53100" shct="0.85" />
<GeneralizedKirkwood type="166" charge="0.24071" shct="0.85" />
<GeneralizedKirkwood type="167" charge="-0.07575" shct="0.72" />
<GeneralizedKirkwood type="168" charge="0.09458" shct="0.85" />
<GeneralizedKirkwood type="169" charge="-0.27255" shct="0.72" />
<GeneralizedKirkwood type="170" charge="0.10149" shct="0.85" />
<GeneralizedKirkwood type="171" charge="0.76984" shct="0.72" />
<GeneralizedKirkwood type="172" charge="-0.74313" shct="0.85" />
<GeneralizedKirkwood type="173" charge="-0.28938" shct="0.79" />
<GeneralizedKirkwood type="174" charge="0.14092" shct="0.85" />
<GeneralizedKirkwood type="175" charge="-0.14215" shct="0.72" />
<GeneralizedKirkwood type="176" charge="0.08383" shct="0.85" />
<GeneralizedKirkwood type="177" charge="-0.22038" shct="0.72" />
<GeneralizedKirkwood type="178" charge="0.07884" shct="0.85" />
<GeneralizedKirkwood type="179" charge="0.14780" shct="0.96" />
<GeneralizedKirkwood type="180" charge="-0.21776" shct="0.72" />
<GeneralizedKirkwood type="181" charge="0.05672" shct="0.85" />
<GeneralizedKirkwood type="182" charge="-0.08975" shct="0.72" />
<GeneralizedKirkwood type="183" charge="0.08202" shct="0.85" />
<GeneralizedKirkwood type="184" charge="-0.21565" shct="0.72" />
<GeneralizedKirkwood type="185" charge="0.08265" shct="0.85" />
<GeneralizedKirkwood type="186" charge="-0.02245" shct="0.72" />
<GeneralizedKirkwood type="187" charge="0.07982" shct="0.85" />
<GeneralizedKirkwood type="188" charge="-0.01637" shct="0.72" />
<GeneralizedKirkwood type="189" charge="0.09822" shct="0.85" />
<GeneralizedKirkwood type="190" charge="0.10000" shct="0.79" />
<GeneralizedKirkwood type="191" charge="0.20727" shct="0.85" />
<GeneralizedKirkwood type="192" charge="-0.14610" shct="0.72" />
<GeneralizedKirkwood type="193" charge="0.06260" shct="0.85" />
<GeneralizedKirkwood type="194" charge="-0.13934" shct="0.72" />
<GeneralizedKirkwood type="195" charge="0.07212" shct="0.85" />
<GeneralizedKirkwood type="196" charge="-0.12642" shct="0.72" />
<GeneralizedKirkwood type="197" charge="0.06261" shct="0.85" />
<GeneralizedKirkwood type="198" charge="0.04761" shct="0.72" />
<GeneralizedKirkwood type="199" charge="0.02822" shct="0.85" />
<GeneralizedKirkwood type="200" charge="-0.20360" shct="0.79" />
<GeneralizedKirkwood type="201" charge="0.08988" shct="0.85" />
<GeneralizedKirkwood type="202" charge="-0.09097" shct="0.72" />
<GeneralizedKirkwood type="203" charge="0.07770" shct="0.85" />
<GeneralizedKirkwood type="204" charge="-0.21722" shct="0.72" />
<GeneralizedKirkwood type="205" charge="0.08258" shct="0.85" />
<GeneralizedKirkwood type="206" charge="-0.01121" shct="0.72" />
<GeneralizedKirkwood type="207" charge="0.07564" shct="0.85" />
<GeneralizedKirkwood type="208" charge="-0.27936" shct="0.79" />
<GeneralizedKirkwood type="209" charge="0.15532" shct="0.85" />
<GeneralizedKirkwood type="210" charge="0.98761" shct="0.72" />
<GeneralizedKirkwood type="211" charge="-0.29224" shct="0.79" />
<GeneralizedKirkwood type="212" charge="0.15787" shct="0.85" />
<GeneralizedKirkwood type="213" charge="-0.08587" shct="0.72" />
<GeneralizedKirkwood type="214" charge="0.08588" shct="0.85" />
<GeneralizedKirkwood type="215" charge="-0.01858" shct="0.72" />
<GeneralizedKirkwood type="216" charge="0.08368" shct="0.85" />
<GeneralizedKirkwood type="217" charge="-0.01249" shct="0.72" />
<GeneralizedKirkwood type="218" charge="0.10208" shct="0.85" />
<GeneralizedKirkwood type="219" charge="0.10000" shct="0.79" />
<GeneralizedKirkwood type="220" charge="0.20727" shct="0.85" />
<GeneralizedKirkwood type="221" charge="-0.19058" shct="0.72" />
<GeneralizedKirkwood type="222" charge="0.07778" shct="0.85" />
<GeneralizedKirkwood type="223" charge="0.68484" shct="0.72" />
<GeneralizedKirkwood type="224" charge="-0.72760" shct="0.85" />
<GeneralizedKirkwood type="225" charge="-0.30948" shct="0.79" />
<GeneralizedKirkwood type="226" charge="0.15474" shct="0.85" />
<GeneralizedKirkwood type="227" charge="-0.26804" shct="0.79" />
<GeneralizedKirkwood type="228" charge="0.11919" shct="0.85" />
<GeneralizedKirkwood type="229" charge="-0.00970" shct="0.72" />
<GeneralizedKirkwood type="230" charge="0.05285" shct="0.85" />
<GeneralizedKirkwood type="231" charge="0.07891" shct="0.79" />
<GeneralizedKirkwood type="231" charge="0.11164" shct="0.79" />
<GeneralizedKirkwood type="231" charge="0.11164" shct="0.79" />
<GeneralizedKirkwood type="232" charge="0.26670" shct="0.85" />
<GeneralizedKirkwood type="232" charge="0.21240" shct="0.85" />
<GeneralizedKirkwood type="232" charge="0.21240" shct="0.85" />
<GeneralizedKirkwood type="233" charge="1.02670" shct="0.72" />
<GeneralizedKirkwood type="234" charge="-0.88956" shct="0.85" />
<GeneralizedKirkwood type="235" charge="0.92336" shct="0.72" />
<GeneralizedKirkwood type="235" charge="0.83309" shct="0.72" />
<GeneralizedKirkwood type="235" charge="0.83309" shct="0.72" />
<GeneralizedKirkwood type="236" charge="-0.58827" shct="0.85" />
<GeneralizedKirkwood type="236" charge="-0.61662" shct="0.85" />
<GeneralizedKirkwood type="236" charge="-0.61662" shct="0.85" />
<GeneralizedKirkwood type="237" charge="-0.46459" shct="0.85" />
<GeneralizedKirkwood type="238" charge="0.24812" shct="0.85" />
<GeneralizedKirkwood type="239" charge="0.07219" shct="0.79" />
<GeneralizedKirkwood type="240" charge="0.23262" shct="0.85" />
<GeneralizedKirkwood type="241" charge="-0.16428" shct="0.72" />
<GeneralizedKirkwood type="242" charge="0.94625" shct="0.72" />
<GeneralizedKirkwood type="243" charge="-0.74794" shct="0.85" />
<GeneralizedKirkwood type="244" charge="0.12611" shct="0.85" />
<GeneralizedKirkwood type="245" charge="-0.04567" shct="0.72" />
<GeneralizedKirkwood type="246" charge="0.10559" shct="0.85" />
<GeneralizedKirkwood type="247" charge="-0.51966" shct="0.85" />
<GeneralizedKirkwood type="248" charge="0.25983" shct="0.85" />
<GeneralizedKirkwood type="249" charge="1.00000" shct="0.8" />
<GeneralizedKirkwood type="250" charge="1.00000" shct="0.8" />
<GeneralizedKirkwood type="251" charge="1.00000" shct="0.8" />
<GeneralizedKirkwood type="252" charge="1.00000" shct="0.8" />
<GeneralizedKirkwood type="253" charge="1.00000" shct="0.8" />
<GeneralizedKirkwood type="254" charge="2.00000" shct="0.8" />
<GeneralizedKirkwood type="255" charge="2.00000" shct="0.8" />
<GeneralizedKirkwood type="256" charge="2.00000" shct="0.8" />
<GeneralizedKirkwood type="257" charge="2.00000" shct="0.8" />
<GeneralizedKirkwood type="258" charge="-1.00000" shct="0.8" />
</AmoebaGeneralizedKirkwoodForce>
<AmoebaWcaDispersionForce epso="0.46024" epsh="0.056484" rmino="0.17025" rminh="0.13275" awater="33.428" slevy="1.0" dispoff="0.026" shctd="0.81" >
<WcaDispersion class="1" radius="0.1855" epsilon="0.46024" />
<WcaDispersion class="2" radius="0.191" epsilon="0.422584" />
<WcaDispersion class="3" radius="0.191" epsilon="0.443504" />
<WcaDispersion class="4" radius="0.1295" epsilon="0.092048" />
<WcaDispersion class="5" radius="0.165" epsilon="0.468608" />
<WcaDispersion class="6" radius="0.147" epsilon="0.108784" />
<WcaDispersion class="7" radius="0.1825" epsilon="0.422584" />
<WcaDispersion class="8" radius="0.191" epsilon="0.422584" />
<WcaDispersion class="9" radius="0.149" epsilon="0.100416" />
<WcaDispersion class="10" radius="0.17025" epsilon="0.46024" />
<WcaDispersion class="11" radius="0.13275" epsilon="0.056484" />
<WcaDispersion class="12" radius="0.20025" epsilon="1.48532" />
<WcaDispersion class="14" radius="0.21" epsilon="1.48532" />
<WcaDispersion class="13" radius="0.15" epsilon="0.110876" />
<WcaDispersion class="15" radius="0.1855" epsilon="0.46024" />
<WcaDispersion class="16" radius="0.191" epsilon="0.422584" />
<WcaDispersion class="17" radius="0.19" epsilon="0.372376" />
<WcaDispersion class="18" radius="0.149" epsilon="0.108784" />
<WcaDispersion class="19" radius="0.17025" epsilon="0.46024" />
<WcaDispersion class="20" radius="0.13275" epsilon="0.056484" />
<WcaDispersion class="22" radius="0.19" epsilon="0.422584" />
<WcaDispersion class="23" radius="0.149" epsilon="0.108784" />
<WcaDispersion class="24" radius="0.1855" epsilon="0.46024" />
<WcaDispersion class="25" radius="0.1295" epsilon="0.092048" />
<WcaDispersion class="26" radius="0.19" epsilon="0.422584" />
<WcaDispersion class="27" radius="0.149" epsilon="0.108784" />
<WcaDispersion class="28" radius="0.19" epsilon="0.422584" />
<WcaDispersion class="29" radius="0.1855" epsilon="0.46024" />
<WcaDispersion class="30" radius="0.191" epsilon="0.443504" />
<WcaDispersion class="31" radius="0.185" epsilon="0.539736" />
<WcaDispersion class="32" radius="0.191" epsilon="0.443504" />
<WcaDispersion class="33" radius="0.165" epsilon="0.468608" />
<WcaDispersion class="34" radius="0.17025" epsilon="0.46024" />
<WcaDispersion class="35" radius="0.13275" epsilon="0.06276" />
<WcaDispersion class="36" radius="0.191" epsilon="0.422584" />
<WcaDispersion class="37" radius="0.1905" epsilon="0.43932" />
<WcaDispersion class="38" radius="0.124" epsilon="0.054392" />
<WcaDispersion class="39" radius="0.1825" epsilon="0.422584" />
<WcaDispersion class="40" radius="0.191" epsilon="0.422584" />
<WcaDispersion class="41" radius="0.188" epsilon="0.43932" />
<WcaDispersion class="42" radius="0.135" epsilon="0.08368" />
<WcaDispersion class="43" radius="0.17025" epsilon="0.46024" />
<WcaDispersion class="44" radius="0.13275" epsilon="0.056484" />
<WcaDispersion class="45" radius="0.119" epsilon="0.33472" />
<WcaDispersion class="46" radius="0.151" epsilon="1.08784" />
<WcaDispersion class="47" radius="0.1855" epsilon="1.4644" />
<WcaDispersion class="48" radius="0.207" epsilon="1.84096" />
<WcaDispersion class="49" radius="0.2185" epsilon="2.21752" />
<WcaDispersion class="50" radius="0.094" epsilon="0.380744" />
<WcaDispersion class="51" radius="0.147" epsilon="1.2552" />
<WcaDispersion class="52" radius="0.1815" epsilon="1.4644" />
<WcaDispersion class="53" radius="0.134" epsilon="0.928848" />
<WcaDispersion class="54" radius="0.2065" epsilon="1.42256" />
</AmoebaWcaDispersionForce>
</ForceField>
<ForceField>
<Info>
<DateGenerated>2014-05-28</DateGenerated>
<Reference>Lee-Ping Wang, Todd J. Martinez and Vijay S. Pande. Building force fields - an automatic, systematic and reproducible approach. Journal of Physical Chemistry Letters, 2014, 5, pp 1885-1891. DOI:10.1021/jz500737m</Reference>
</Info>
<AtomTypes>
<Type name="tip3p-fb-O" class="OW" element="O" mass="15.99943"/>
<Type name="tip3p-fb-H" class="HW" element="H" mass="1.007947"/>
</AtomTypes>
<Residues>
<Residue name="HOH">
<Atom name="O" type="tip3p-fb-O"/>
<Atom name="H1" type="tip3p-fb-H"/>
<Atom name="H2" type="tip3p-fb-H"/>
<Bond from="0" to="1"/>
<Bond from="0" to="2"/>
</Residue>
</Residues>
<HarmonicBondForce>
<Bond class1="OW" class2="HW" length="0.101181082494" k="462750.4"/>
</HarmonicBondForce>
<HarmonicAngleForce>
<Angle class1="HW" class2="OW" class3="HW" angle="1.88754640288" k="836.8"/>
</HarmonicAngleForce>
<NonbondedForce coulomb14scale="0.833333" lj14scale="0.5">
<Atom type="tip3p-fb-O" charge="-0.848448690103" sigma="0.317796456355" epsilon="0.652143528104" />
<Atom type="tip3p-fb-H" charge="0.4242243450515" sigma="1" epsilon="0" />
</NonbondedForce>
</ForceField>
<ForceField>
<Info>
<DateGenerated>2014-05-28</DateGenerated>
<Reference>Lee-Ping Wang, Todd J. Martinez and Vijay S. Pande. Building force fields - an automatic, systematic and reproducible approach. Journal of Physical Chemistry Letters, 2014, 5, pp 1885-1891. DOI:10.1021/jz500737m</Reference>
</Info>
<AtomTypes>
<Type name="tip4p-fb-O" class="OW" element="O" mass="15.99943"/>
<Type name="tip4p-fb-H" class="HW" element="H" mass="1.007947"/>
<Type name="tip4p-fb-M" class="MW" mass="0"/>
</AtomTypes>
<Residues>
<Residue name="HOH">
<Atom name="O" type="tip4p-fb-O"/>
<Atom name="H1" type="tip4p-fb-H"/>
<Atom name="H2" type="tip4p-fb-H"/>
<Atom name="M" type="tip4p-fb-M"/>
<VirtualSite type="average3" index="3" atom1="0" atom2="1" atom3="2" weight1="8.203146574531e-01" weight2="8.984267127345e-02" weight3="8.984267127345e-02" />
<Bond from="0" to="1"/>
<Bond from="0" to="2"/>
</Residue>
</Residues>
<HarmonicBondForce>
<Bond class1="OW" class2="HW" length="0.09572" k="462750.4"/>
</HarmonicBondForce>
<HarmonicAngleForce>
<Angle class1="HW" class2="OW" class3="HW" angle="1.82421813418" k="836.8"/>
</HarmonicAngleForce>
<NonbondedForce coulomb14scale="0.833333" lj14scale="0.5">
<Atom type="tip4p-fb-O" charge="0" sigma="3.165552430462e-01" epsilon="7.492790213533e-01" />
<Atom type="tip4p-fb-H" charge="5.258681106763e-01" sigma="1" epsilon="0" />
<Atom type="tip4p-fb-M" charge="-1.0517362213526e+00" sigma="1" epsilon="0" />
</NonbondedForce>
</ForceField>
...@@ -6,7 +6,7 @@ Simbios, the NIH National Center for Physics-Based Simulation of ...@@ -6,7 +6,7 @@ Simbios, the NIH National Center for Physics-Based Simulation of
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) 2012-2013 Stanford University and the Authors. Portions copyright (c) 2012-2014 Stanford University and the Authors.
Authors: Peter Eastman, Mark Friedrichs Authors: Peter Eastman, Mark Friedrichs
Contributors: Contributors:
...@@ -1485,6 +1485,104 @@ class CustomTorsionGenerator: ...@@ -1485,6 +1485,104 @@ class CustomTorsionGenerator:
parsers["CustomTorsionForce"] = CustomTorsionGenerator.parseElement parsers["CustomTorsionForce"] = CustomTorsionGenerator.parseElement
## @private
class CustomNonbondedGenerator:
"""A CustomNonbondedGenerator constructs a CustomNonbondedForce."""
def __init__(self, energy, bondCutoff):
self.energy = energy
self.bondCutoff = bondCutoff
self.typeMap = {}
self.globalParams = {}
self.perParticleParams = []
self.functions = []
@staticmethod
def parseElement(element, ff):
generator = CustomNonbondedGenerator(element.attrib['energy'], int(element.attrib['bondCutoff']))
ff._forces.append(generator)
for param in element.findall('GlobalParameter'):
generator.globalParams[param.attrib['name']] = float(param.attrib['defaultValue'])
for param in element.findall('PerParticleParameter'):
generator.perParticleParams.append(param.attrib['name'])
for atom in element.findall('Atom'):
types = ff._findAtomTypes(atom, 1)
if None not in types:
values = [float(atom.attrib[param]) for param in generator.perParticleParams]
for t in types[0]:
generator.typeMap[t] = values
def createForce(self, sys, data, nonbondedMethod, nonbondedCutoff, args):
methodMap = {NoCutoff:mm.CustomNonbondedForce.NoCutoff,
CutoffNonPeriodic:mm.CustomNonbondedForce.CutoffNonPeriodic,
CutoffPeriodic:mm.CustomNonbondedForce.CutoffPeriodic}
if nonbondedMethod not in methodMap:
raise ValueError('Illegal nonbonded method for CustomNonbondedForce')
force = mm.CustomNonbondedForce(self.energy)
for param in self.globalParams:
force.addGlobalParameter(param, self.globalParams[param])
for param in self.perParticleParams:
force.addPerParticleParameter(param)
for (name, type, values, params) in self.functions:
if type == 'Continuous1D':
force.addTabulatedFunction(name, mm.Continuous1DFunction(values, params['min'], params['max']))
elif type == 'Continuous2D':
force.addTabulatedFunction(name, mm.Continuous2DFunction(params['xsize'], params['ysize'], values, params['xmin'], params['xmax'], params['ymin'], params['ymax']))
elif type == 'Continuous3D':
force.addTabulatedFunction(name, mm.Continuous2DFunction(params['xsize'], params['ysize'], params['zsize'], values, params['xmin'], params['xmax'], params['ymin'], params['ymax'], params['zmin'], params['zmax']))
elif type == 'Discrete1D':
force.addTabulatedFunction(name, mm.Discrete1DFunction(values))
elif type == 'Discrete2D':
force.addTabulatedFunction(name, mm.Discrete2DFunction(params['xsize'], params['ysize'], values))
elif type == 'Discrete3D':
force.addTabulatedFunction(name, mm.Discrete2DFunction(params['xsize'], params['ysize'], params['zsize'], values))
for atom in data.atoms:
t = data.atomType[atom]
if t in self.typeMap:
values = self.typeMap[t]
force.addParticle(self.typeMap[t])
else:
raise ValueError('No CustomNonbonded parameters defined for atom type '+t)
force.setNonbondedMethod(methodMap[nonbondedMethod])
force.setCutoffDistance(nonbondedCutoff)
sys.addForce(force)
def postprocessSystem(self, sys, data, args):
# Create exceptions based on bonds, virtual sites, and Drude particles.
if self.bondCutoff == 0:
return
bondIndices = []
for bond in data.bonds:
bondIndices.append((bond.atom1, bond.atom2))
for i in range(sys.getNumParticles()):
if sys.isVirtualSite(i):
site = sys.getVirtualSite(i)
for j in range(site.getNumParticles()):
bondIndices.append((i, site.getParticle(j)))
drude = [f for f in sys.getForces() if isinstance(f, mm.DrudeForce)]
if len(drude) > 0:
drude = drude[0]
# For purposes of creating exceptions, a Drude particle is "bonded" to anything
# its parent atom is bonded to.
drudeMap = {}
for i in range(drude.getNumParticles()):
params = drude.getParticleParameters(i)
drudeMap[params[1]] = params[0]
for atom1, atom2 in bondIndices:
drude1 = drudeMap[atom1] if atom1 in drudeMap else None
drude2 = drudeMap[atom2] if atom2 in drudeMap else None
if drude1 is not None:
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.CustomNonbondedForce)][0]
nonbonded.createExclusionsFromBonds(bondIndices, self.bondCutoff)
parsers["CustomNonbondedForce"] = CustomNonbondedGenerator.parseElement
## @private ## @private
class CustomGBGenerator: class CustomGBGenerator:
"""A CustomGBGenerator constructs a CustomGBForce.""" """A CustomGBGenerator constructs a CustomGBForce."""
...@@ -1493,7 +1591,6 @@ class CustomGBGenerator: ...@@ -1493,7 +1591,6 @@ class CustomGBGenerator:
self.typeMap = {} self.typeMap = {}
self.globalParams = {} self.globalParams = {}
self.perParticleParams = [] self.perParticleParams = []
self.paramValues = []
self.computedValues = [] self.computedValues = []
self.energyTerms = [] self.energyTerms = []
self.functions = [] self.functions = []
...@@ -2517,9 +2614,10 @@ class AmoebaTorsionTorsionGenerator: ...@@ -2517,9 +2614,10 @@ class AmoebaTorsionTorsionGenerator:
gridRow.append(float(gridEntry.attrib['angle1'])) gridRow.append(float(gridEntry.attrib['angle1']))
gridRow.append(float(gridEntry.attrib['angle2'])) gridRow.append(float(gridEntry.attrib['angle2']))
gridRow.append(float(gridEntry.attrib['f'])) gridRow.append(float(gridEntry.attrib['f']))
gridRow.append(float(gridEntry.attrib['fx'])) if 'fx' in gridEntry.attrib:
gridRow.append(float(gridEntry.attrib['fy'])) gridRow.append(float(gridEntry.attrib['fx']))
gridRow.append(float(gridEntry.attrib['fxy'])) gridRow.append(float(gridEntry.attrib['fy']))
gridRow.append(float(gridEntry.attrib['fxy']))
gridCol.append(gridRow) gridCol.append(gridRow)
gridColIndex += 1 gridColIndex += 1
......
...@@ -6,7 +6,7 @@ Simbios, the NIH National Center for Physics-Based Simulation of ...@@ -6,7 +6,7 @@ Simbios, the NIH National Center for Physics-Based Simulation of
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) 2012-2013 Stanford University and the Authors. Portions copyright (c) 2012-2014 Stanford University and the Authors.
Authors: Peter Eastman Authors: Peter Eastman
Contributors: Contributors:
...@@ -745,6 +745,12 @@ class GromacsTopFile(object): ...@@ -745,6 +745,12 @@ class GromacsTopFile(object):
atom1params = nb.getParticleParameters(baseAtomIndex+atoms[0]) atom1params = nb.getParticleParameters(baseAtomIndex+atoms[0])
atom2params = nb.getParticleParameters(baseAtomIndex+atoms[1]) atom2params = nb.getParticleParameters(baseAtomIndex+atoms[1])
exceptions.append((baseAtomIndex+atoms[0], baseAtomIndex+atoms[1], atom1params[0]*atom2params[0]*fudgeQQ, params[0], params[1])) exceptions.append((baseAtomIndex+atoms[0], baseAtomIndex+atoms[1], atom1params[0]*atom2params[0]*fudgeQQ, params[0], params[1]))
for fields in moleculeType.exclusions:
atoms = [int(x)-1 for x in fields]
for atom in atoms[1:]:
if atom > atoms[0]:
exceptions.append((baseAtomIndex+atoms[0], baseAtomIndex+atom, 0, 0, 0))
# Create nonbonded exceptions. # Create nonbonded exceptions.
......
...@@ -40,15 +40,14 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. ...@@ -40,15 +40,14 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#============================================================================================= #=============================================================================================
import os import os
import os.path
import re import re
import math from math import ceil, cos, sin, asin, sqrt, pi
import warnings import warnings
try: try:
import numpy import numpy as np
except: except:
pass np = None
import simtk.unit as units import simtk.unit as units
import simtk.openmm import simtk.openmm
...@@ -74,6 +73,9 @@ POINTER_LABELS = """ ...@@ -74,6 +73,9 @@ POINTER_LABELS = """
# Pointer labels (above) as a list, not string. # Pointer labels (above) as a list, not string.
POINTER_LABEL_LIST = POINTER_LABELS.replace(',', '').split() POINTER_LABEL_LIST = POINTER_LABELS.replace(',', '').split()
VELSCALE = 20.455 # velocity conversion factor to angstroms/picosecond
TINY = 1.0e-8
class PrmtopLoader(object): class PrmtopLoader(object):
"""Parsed AMBER prmtop file. """Parsed AMBER prmtop file.
...@@ -83,14 +85,14 @@ class PrmtopLoader(object): ...@@ -83,14 +85,14 @@ class PrmtopLoader(object):
Parse a prmtop file of alanine dipeptide in implicit solvent. Parse a prmtop file of alanine dipeptide in implicit solvent.
>>> import os, os.path >>> import os
>>> directory = os.path.join(os.getenv('YANK_INSTALL_DIR'), 'test', 'systems', 'alanine-dipeptide-gbsa') >>> directory = os.path.join(os.getenv('YANK_INSTALL_DIR'), 'test', 'systems', 'alanine-dipeptide-gbsa')
>>> prmtop_filename = os.path.join(directory, 'alanine-dipeptide.prmtop') >>> prmtop_filename = os.path.join(directory, 'alanine-dipeptide.prmtop')
>>> prmtop = PrmtopLoader(prmtop_filename) >>> prmtop = PrmtopLoader(prmtop_filename)
Parse a prmtop file of alanine dipeptide in explicit solvent. Parse a prmtop file of alanine dipeptide in explicit solvent.
>>> import os, os.path >>> import os
>>> directory = os.path.join(os.getenv('YANK_INSTALL_DIR'), 'test', 'systems', 'alanine-dipeptide-explicit') >>> directory = os.path.join(os.getenv('YANK_INSTALL_DIR'), 'test', 'systems', 'alanine-dipeptide-explicit')
>>> prmtop_filename = os.path.join(directory, 'alanine-dipeptide.prmtop') >>> prmtop_filename = os.path.join(directory, 'alanine-dipeptide.prmtop')
>>> prmtop = PrmtopLoader(prmtop_filename) >>> prmtop = PrmtopLoader(prmtop_filename)
...@@ -437,7 +439,7 @@ class PrmtopLoader(object): ...@@ -437,7 +439,7 @@ class PrmtopLoader(object):
(rVdwI, epsilonI) = nonbondTerms[iAtom] (rVdwI, epsilonI) = nonbondTerms[iAtom]
(rVdwL, epsilonL) = nonbondTerms[lAtom] (rVdwL, epsilonL) = nonbondTerms[lAtom]
rMin = (rVdwI+rVdwL) rMin = (rVdwI+rVdwL)
epsilon = math.sqrt(epsilonI*epsilonL) epsilon = sqrt(epsilonI*epsilonL)
try: try:
iScee = float(self._raw_data["SCEE_SCALE_FACTOR"][iidx]) iScee = float(self._raw_data["SCEE_SCALE_FACTOR"][iidx])
except KeyError: except KeyError:
...@@ -708,7 +710,7 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode ...@@ -708,7 +710,7 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
l2 = bond[1] l2 = bond[1]
# Compute the distance between atoms and add a constraint # Compute the distance between atoms and add a constraint
length = math.sqrt(l1*l1 + l2*l2 - 2*l1*l2*math.cos(aMin)) length = sqrt(l1*l1 + l2*l2 - 2*l1*l2*cos(aMin))
system.addConstraint(iAtom, kAtom, length) system.addConstraint(iAtom, kAtom, length)
if flexibleConstraints or not constrained: if flexibleConstraints or not constrained:
force.addAngle(iAtom, jAtom, kAtom, aMin, 2*k) force.addAngle(iAtom, jAtom, kAtom, aMin, 2*k)
...@@ -739,10 +741,17 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode ...@@ -739,10 +741,17 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
# System is periodic. # System is periodic.
# Set periodic box vectors for periodic system # Set periodic box vectors for periodic system
(boxBeta, boxX, boxY, boxZ) = prmtop.getBoxBetaAndDimensions() (boxBeta, boxX, boxY, boxZ) = prmtop.getBoxBetaAndDimensions()
d0 = units.Quantity(0.0, units.angstroms) boxBeta = boxBeta.value_in_unit(units.degrees)
xVec = units.Quantity((boxX, d0, d0)) boxX = boxX.value_in_unit(units.angstroms)
yVec = units.Quantity((d0, boxY, d0)) boxY = boxY.value_in_unit(units.angstroms)
zVec = units.Quantity((d0, d0, boxZ)) boxZ = boxZ.value_in_unit(units.angstroms)
tmp = [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]]
_box_vectors_from_lengths_angles([boxX, boxY, boxZ],
[boxBeta, boxBeta, boxBeta],
tmp)
xVec = units.Quantity(tmp[0], units.angstroms)
yVec = units.Quantity(tmp[1], units.angstroms)
zVec = units.Quantity(tmp[2], units.angstroms)
system.setDefaultPeriodicBoxVectors(xVec, yVec, zVec) system.setDefaultPeriodicBoxVectors(xVec, yVec, zVec)
# Set cutoff. # Set cutoff.
...@@ -848,13 +857,13 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode ...@@ -848,13 +857,13 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
if len(waterO[res]) == 1 and len(waterH[res]) == 2: if len(waterO[res]) == 1 and len(waterH[res]) == 2:
if len(waterEP[res]) == 1: if len(waterEP[res]) == 1:
# Four point water # Four point water
weightH = distOE[res]/math.sqrt(distOH[res]**2-(0.5*distHH[res])**2) weightH = distOE[res]/sqrt(distOH[res]**2-(0.5*distHH[res])**2)
system.setVirtualSite(waterEP[res][0], mm.ThreeParticleAverageSite(waterO[res][0], waterH[res][0], waterH[res][1], 1-weightH, weightH/2, weightH/2)) system.setVirtualSite(waterEP[res][0], mm.ThreeParticleAverageSite(waterO[res][0], waterH[res][0], waterH[res][1], 1-weightH, weightH/2, weightH/2))
elif len(waterEP[res]) == 2: elif len(waterEP[res]) == 2:
# Five point water # Five point water
weightH = cosOOP*distOE[res]/math.sqrt(distOH[res]**2-(0.5*distHH[res])**2) weightH = cosOOP*distOE[res]/sqrt(distOH[res]**2-(0.5*distHH[res])**2)
angleHOH = 2*math.asin(0.5*distHH[res]/distOH[res]) angleHOH = 2*asin(0.5*distHH[res]/distOH[res])
lenCross = (distOH[res]**2)*math.sin(angleHOH) lenCross = (distOH[res]**2)*sin(angleHOH)
weightCross = sinOOP*distOE[res]/lenCross weightCross = sinOOP*distOE[res]/lenCross
system.setVirtualSite(waterEP[res][0], mm.OutOfPlaneSite(waterO[res][0], waterH[res][0], waterH[res][1], weightH/2, weightH/2, weightCross)) system.setVirtualSite(waterEP[res][0], mm.OutOfPlaneSite(waterO[res][0], waterH[res][0], waterH[res][1], weightH/2, weightH/2, weightCross))
system.setVirtualSite(waterEP[res][1], mm.OutOfPlaneSite(waterO[res][0], waterH[res][0], waterH[res][1], weightH/2, weightH/2, -weightCross)) system.setVirtualSite(waterEP[res][1], mm.OutOfPlaneSite(waterO[res][0], waterH[res][0], waterH[res][1], weightH/2, weightH/2, -weightCross))
...@@ -917,134 +926,395 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode ...@@ -917,134 +926,395 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
return system return system
#============================================================================================= #=============================================================================================
# AMBER INPCRD loader # AMBER INPCRD loader classes
#============================================================================================= #=============================================================================================
def readAmberCoordinates(filename, read_box=False, read_velocities=False, verbose=False, asNumpy=False): class AmberAsciiRestart(object):
"""
Class responsible for parsing Amber coordinates in the ASCII format.
Automatically detects the presence of velocities or box parameters in the
file.
Parameters
----------
filename : str
Name of the restart file
asNumpy : bool (False)
Load the coordinates, velocities, and box as numpy ndarray objects
Attributes
----------
coordinates : natom x 3 array, Quantity
Particle positions with units of length
velocities : natom x 3 array, Quantity
Particle velocities with units of length per time (None if velocities
are not present in the inpcrd file)
boxVectors : 3 x 3 array, Quantity
Box vectors with units of length (None if no box is present in the
inpcrd file)
time : float, Quantity
Simulation time (None if not present) with units of time
title : str
Title of the inpcrd file
filename : str
Name of the file we are parsing
natom : int
Number of atoms in the inpcrd file
Raises
------
`IOError' if the file does not exist
`TypeError' if the format of the file is not recognized
`ValueError' if not all fields are numbers (for example, if a field is
filled with ****'s)
`IndexError' if the file is empty
`ImportError' if numpy is requested but could not be imported
Example
-------
>>> f = AmberAsciiRestart('alanine-dipeptide.inpcrd')
>>> coordinates = f.coordinates
"""
def __init__(self, filename, asNumpy=False):
# Make sure numpy is available if requested
if asNumpy and np is None:
raise ImportError('asNumpy=True: numpy is not available')
self._asNumpy = asNumpy
self.filename = filename
with open(filename, 'r') as f:
lines = f.readlines()
# Get rid of trailing blank lines
while lines and not lines[-1].strip():
lines.pop()
self._parse(lines)
def __str__(self):
return self.filename
def _parse(self, lines):
""" Parses through the inpcrd file """
global VELSCALE
self.title = lines[0].strip()
self.time = None
try:
words = lines[1].split()
self.natom = int(words[0])
except (IndexError, ValueError):
raise TypeError('Unrecognized file type [%s]' % self.filename)
if len(words) >= 2:
self.time = float(words[1]) * units.picoseconds
if len(lines) == int(ceil(self.natom / 2.0) + 2):
hasbox = hasvels = False
self.boxVectors = self.velocities = None
elif self.natom in (1, 2) and len(lines) == 4:
# This is the _only_ case where line counting does not work -- there
# is either 1 or 2 atoms and there are 4 lines. The 1st 3 lines are
# the title, natom/time, and coordinates. The 4th are almost always
# velocities since Amber does not make it easy to make a periodic
# system with only 2 atoms. If natom is 1, the 4th line is either a
# velocity (3 #'s) or a box (6 #'s). If natom is 2, it is a bit
# ambiguous. However, velocities (which are scaled by 20.445) have a
# ~0% chance of being 60+, so we can pretty easily tell if the last
# line has box dimensions and angles or velocities. I cannot
# envision a _plausible_ scenario where the detection here will fail
# in real life.
line = lines[3]
if self.natom == 1:
tmp = [line[i:i+12] for i in range(0, 72, 12) if line[i:i+12]]
if len(tmp) == 3:
hasvels = True
hasbox = False
self.boxVectors = False
elif len(tmp) == 6:
hasbox = True
hasvels = False
self.velocities = None
else:
raise TypeError('Unrecognized line in restart file %s' %
self.filename)
else:
# Ambiguous case
tmp = [float(line[i:i+12]) >= 60.0 for i in range(0, 72, 12)]
if any(tmp):
hasbox = True
hasvels = False
self.velocities = False
else:
hasvels = True
hasbox = False
self.boxVectors = False
elif len(lines) == int(ceil(self.natom / 2.0) + 3):
hasbox = True
hasvels = False
self.velocities = None
elif len(lines) == int(2 * ceil(self.natom / 2.0) + 2):
hasbox = False
self.boxVectors = None
hasvels = True
elif len(lines) == int(2 * ceil(self.natom / 2.0) + 3):
hasbox = hasvels = True
else:
raise TypeError('Badly formatted restart file. Has %d lines '
'for %d atoms.' % (len(self.lines), self.natom))
if self._asNumpy:
coordinates = np.zeros((self.natom, 3), np.float32)
if hasvels:
velocities = np.zeros((self.natom, 3), np.float32)
if hasbox:
boxVectors = np.zeros((3, 3), np.float32)
else:
coordinates = [[0.0, 0.0, 0.0] for i in range(self.natom)]
if hasvels:
velocities = [[0.0, 0.0, 0.0] for i in range(self.natom)]
if hasbox:
boxVectors = [[0.0, 0.0, 0.0] for i in range(3)]
# Now it's time to parse. Coordinates first
startline = 2
endline = startline + int(ceil(self.natom / 2.0))
idx = 0
for i in range(startline, endline):
line = lines[i]
coordinates[idx][0] = float(line[ 0:12])
coordinates[idx][1] = float(line[12:24])
coordinates[idx][2] = float(line[24:36])
idx += 1
if idx < self.natom:
coordinates[idx][0] = float(line[36:48])
coordinates[idx][1] = float(line[48:60])
coordinates[idx][2] = float(line[60:72])
idx += 1
self.coordinates = units.Quantity(coordinates, units.angstroms)
startline = endline
# Now it's time to parse velocities if we have them
if hasvels:
endline = startline + int(ceil(self.natom / 2.0))
idx = 0
for i in range(startline, endline):
line = lines[i]
velocities[idx][0] = float(line[ 0:12]) * VELSCALE
velocities[idx][1] = float(line[12:24]) * VELSCALE
velocities[idx][2] = float(line[24:36]) * VELSCALE
idx += 1
if idx < self.natom:
velocities[idx][0] = float(line[36:48]) * VELSCALE
velocities[idx][1] = float(line[48:60]) * VELSCALE
velocities[idx][2] = float(line[60:72]) * VELSCALE
idx += 1
startline = endline
self.velocities = units.Quantity(velocities,
units.angstroms/units.picoseconds)
if hasbox:
line = lines[startline]
try:
tmp = [float(line[i:i+12]) for i in range(0, 72, 12)]
except (IndexError, ValueError):
raise ValueError('Could not parse box line in %s' %
self.filename)
lengths = tmp[:3]
angles = tmp[3:]
_box_vectors_from_lengths_angles(lengths, angles, boxVectors)
self.boxVectors = units.Quantity(boxVectors, units.angstroms)
class AmberNetcdfRestart(object):
"""
Amber restart/inpcrd file in the NetCDF format (full double-precision
coordinates, velocities, and unit cell parameters). Reads NetCDF restarts
written by LEaP and pmemd/sander. Requires scipy to parse NetCDF files.
Parameters
----------
filename : str
Name of the restart file
asNumpy : bool (False)
Load the coordinates, velocities, and box as numpy ndarray objects
Attributes
----------
coordinates : natom x 3 array, Quantity
Particle positions with units of length
velocities : natom x 3 array, Quantity
Particle velocities with units of length per time (None if velocities
are not present in the inpcrd file)
boxVectors : 3 x 3 array, Quantity
Box vectors with units of length (None if no box is present in the
inpcrd file)
time : float, Quantity
Simulation time (None if not present) with units of time
title : str
Title of the inpcrd file
filename : str
Name of the file we are parsing
natom : int
Number of atoms in the inpcrd file
Raises
------
`IOError' if the file does not exist
`TypeError' if the file is not a NetCDF v3 file
`ImportError' if scipy is not available
Example
-------
>>> f = AmberNetcdfRestart('alanine-dipeptide.ncrst')
>>> coordinates = f.coordinates
"""
def __init__(self, filename, asNumpy=False):
try:
from scipy.io.netcdf import NetCDFFile
except ImportError:
raise ImportError('scipy is necessary to parse NetCDF restarts')
self.filename = filename
self.velocities = self.boxVectors = self.time = None
# Extract the information from the NetCDF file. We need to make copies
# here because the NetCDF variables are mem-mapped, but is only mapped
# to valid memory while the file handle is open. Since the context
# manager GCs the ncfile handle, the memory for the original variables
# is no longer valid. So copy those arrays while the handle is still
# open. This is unnecessary in scipy v.0.12 and lower because NetCDFFile
# accidentally leaks the file handle, but that was 'fixed' in 0.13. This
# fix taken from MDTraj
ncfile = NetCDFFile(filename, 'r')
try:
self.natom = ncfile.dimensions['atom']
self.coordinates = np.array(ncfile.variables['coordinates'][:])
if 'velocities' in ncfile.variables:
vels = ncfile.variables['velocities']
self.velocities = np.array(vels[:]) * vels.scale_factor
if ('cell_lengths' in ncfile.variables and
'cell_angles' in ncfile.variables):
self.boxVectors = np.zeros((3,3), np.float32)
_box_vectors_from_lengths_angles(
ncfile.variables['cell_lengths'][:],
ncfile.variables['cell_angles'][:],
self.boxVectors,
)
if 'time' in ncfile.variables:
self.time = ncfile.variables['time'].getValue()
finally:
ncfile.close()
# They are already numpy -- convert to list if we don't want numpy
if not asNumpy:
self.coordinates = self.coordinates.tolist()
if self.velocities is not None:
self.velocities = self.velocities.tolist()
if self.boxVectors is not None:
self.boxVectors = self.boxVectors.tolist()
# Now add the units
self.coordinates = units.Quantity(self.coordinates, units.angstroms)
if self.velocities is not None:
self.velocities = units.Quantity(self.velocities,
units.angstroms/units.picoseconds)
if self.boxVectors is not None:
self.boxVectors = units.Quantity(self.boxVectors, units.angstroms)
self.time = units.Quantity(self.time, units.picosecond)
def _box_vectors_from_lengths_angles(lengths, angles, boxVectors):
"""
Converts lengths and angles into a series of box vectors and modifies
boxVectors in-place (it must be a mutable sequence)
Parameters
----------
lengths : 3-element array of floats
Lengths of the 3 periodic box vectors
angles : 3-element array of floats
Angles (in degrees) between the 3 periodic box vectors
boxVectors : mutable 3x3 sequence
"""
alpha = angles[0] * pi / 180.0
beta = angles[1] * pi / 180.0
gamma = angles[2] * pi / 180.0
boxVectors[0][0] = lengths[0]
boxVectors[1][0] = lengths[1] * cos(gamma)
boxVectors[1][1] = lengths[1] * sin(gamma)
boxVectors[2][0] = cx = lengths[2] * cos(beta)
boxVectors[2][1] = cy = lengths[2] * (cos(alpha) - cos(beta) * cos(gamma))
boxVectors[2][2] = sqrt(lengths[2]*lengths[2] - cx*cx - cy*cy)
boxVectors[0][1] = boxVectors[0][2] = boxVectors[1][2] = 0.0
# Now make sure any vector close to zero is zero exactly
for i in range(3):
for j in range(3):
if abs(boxVectors[i][j]) < TINY:
boxVectors[i][j] = 0.0
def readAmberCoordinates(filename, asNumpy=False):
""" """
Read atomic coordinates (and optionally, box vectors) from Amber formatted coordinate file. Read atomic coordinates (and optionally, box vectors) from Amber formatted coordinate file.
ARGUMENTS ARGUMENTS
filename (string) - name of Amber coordinates file to be read in filename (string) - name of Amber coordinates file to be read in
system (simtk.openmm.System) - System object for which coordinates are to be read
OPTIONAL ARGUMENTS OPTIONAL ARGUMENTS
verbose (boolean) - if True, will print out verbose information about the file being read
asNumpy (boolean) - if True, results will be returned as Numpy arrays instead of lists of Vec3s asNumpy (boolean) - if True, results will be returned as Numpy arrays instead of lists of Vec3s
RETURNS
coordinates, velocities, boxVectors
The velocities and boxVectors will be None if they are not found in the
restart file
EXAMPLES EXAMPLES
Read coordinates in vacuum. Read coordinates in vacuum.
>>> directory = os.path.join(os.getenv('YANK_INSTALL_DIR'), 'test', 'systems', 'alanine-dipeptide-gbsa') >>> directory = os.path.join(os.getenv('YANK_INSTALL_DIR'), 'test', 'systems', 'alanine-dipeptide-gbsa')
>>> crd_filename = os.path.join(directory, 'alanine-dipeptide.inpcrd') >>> crd_filename = os.path.join(directory, 'alanine-dipeptide.inpcrd')
>>> coordinates = readAmberCoordinates(crd_filename) >>> coordinates, velocities, box_vectors = readAmberCoordinates(crd_filename)
Read coordinates in solvent. Read coordinates in solvent.
>>> directory = os.path.join(os.getenv('YANK_INSTALL_DIR'), 'test', 'systems', 'alanine-dipeptide-explicit') >>> directory = os.path.join(os.getenv('YANK_INSTALL_DIR'), 'test', 'systems', 'alanine-dipeptide-explicit')
>>> crd_filename = os.path.join(directory, 'alanine-dipeptide.inpcrd') >>> crd_filename = os.path.join(directory, 'alanine-dipeptide.inpcrd')
>>> [coordinates, box_vectors] = readAmberCoordinates(crd_filename, read_box=True) >>> coordinates, velocities, box_vectors = readAmberCoordinates(crd_filename)
""" """
# Open coordinate file for reading. try:
infile = open(filename, 'r') crdfile = AmberNetcdfRestart(filename)
except ImportError:
# Read title # See if it's an ASCII file. If so, no need to complain
title = infile.readline().strip() try:
if verbose: print "title: '%s'" % title crdfile = AmberAsciiRestart(filename)
except TypeError:
# Read number of atoms raise TypeError('Problem parsing %s as an ASCII Amber restart file '
natoms = int(infile.readline().split()[0]) 'and scipy could not be imported to try reading as '
if verbose: print "%d atoms" % natoms 'a NetCDF restart file.' % filename)
except (IndexError, ValueError):
# Allocate storage for coordinates raise TypeError('Could not parse Amber ASCII restart file %s' %
coordinates = [] filename)
except ImportError:
# Read coordinates raise ImportError('Could not find numpy; cannot use asNumpy=True')
mm = simtk.openmm except TypeError:
natoms_read = 0 # We had scipy, but this is not a NetCDF v3 file. Try as ASCII now
while (natoms_read < natoms): try:
line = infile.readline() crdfile = AmberAsciiRestart(filename)
if len(line) == 0: except TypeError:
raise ValueError("Unexpected end of file while reading coordinates") raise TypeError('Problem parsing %s as an ASCII Amber restart file'
line = line.strip() % filename)
elements = line.split() except (IndexError, ValueError):
while (len(elements) > 0): raise TypeError('Could not parse Amber ASCII restart file %s' %
coordinates.append(mm.Vec3(float(elements.pop(0)), float(elements.pop(0)), float(elements.pop(0)))) filename)
natoms_read += 1 # Import error cannot happen, since we had scipy which has numpy as a
if asNumpy: # prereq. Do not catch that exception (only catch what you intend to
newcoords = numpy.zeros([natoms,3], numpy.float32) # catch...)
for i in range(len(coordinates)):
for j in range(3): # We got here... one of the file types worked. Return the coordinates,
newcoords[i,j] = coordinates[i][j] # velocities, and boxVectors
coordinates = newcoords return crdfile.coordinates, crdfile.velocities, crdfile.boxVectors
# Assign units.
coordinates = units.Quantity(coordinates, units.angstroms)
# Read velocities if requested.
velocities = None
if (read_velocities):
# Read velocities
velocities = []
natoms_read = 0
while (natoms_read < natoms):
line = infile.readline()
if len(line) == 0:
raise ValueError("Unexpected end of file while reading velocities")
line = line.strip()
elements = line.split()
while (len(elements) > 0):
velocities.append(20.455*mm.Vec3(float(elements.pop(0)), float(elements.pop(0)), float(elements.pop(0))))
natoms_read += 1
if asNumpy:
newvel = numpy.zeros([natoms,3], numpy.float32)
for i in range(len(velocities)):
for j in range(3):
newvel[i,j] = velocities[i][j]
velocities = newvel
# Assign units.
velocities = units.Quantity(velocities, units.angstroms/units.picoseconds)
# Read box size if present
box_vectors = None
if (read_box):
line = infile.readline()
if len(line) == 0:
raise ValueError("Unexpected end of file while reading box vectors")
line = line.strip()
elements = line.split()
nelements = len(elements)
box_dimensions = [0.0]*nelements
for i in range(nelements):
box_dimensions[i] = float(elements[i])
# TODO: Deal with non-standard box sizes.
if nelements == 6:
if asNumpy:
a = units.Quantity(numpy.array([box_dimensions[0], 0.0, 0.0]), units.angstroms)
b = units.Quantity(numpy.array([0.0, box_dimensions[1], 0.0]), units.angstroms)
c = units.Quantity(numpy.array([0.0, 0.0, box_dimensions[2]]), units.angstroms)
else:
a = units.Quantity(mm.Vec3(box_dimensions[0], 0.0, 0.0), units.angstroms)
b = units.Quantity(mm.Vec3(0.0, box_dimensions[1], 0.0), units.angstroms)
c = units.Quantity(mm.Vec3(0.0, 0.0, box_dimensions[2]), units.angstroms)
box_vectors = [a,b,c]
else:
raise Exception("Don't know what to do with box vectors: %s" % line)
# Close file
infile.close()
if box_vectors and velocities:
return (coordinates, box_vectors, velocities)
if box_vectors:
return (coordinates, box_vectors)
if velocities:
return (coordinates, velocities)
return coordinates
#============================================================================================= #=============================================================================================
# MAIN AND TESTS # MAIN AND TESTS
......
...@@ -421,8 +421,10 @@ class ResidueList(list): ...@@ -421,8 +421,10 @@ class ResidueList(list):
if self._last_residue is None: if self._last_residue is None:
res = self._last_residue = Residue(resname, resnum) res = self._last_residue = Residue(resname, resnum)
list.append(self, res) list.append(self, res)
elif self._last_residue != (resname, resnum): elif (self._last_residue != (resname, resnum) or
if self._last_residue.idx == resnum: system != self._last_residue.system):
if (self._last_residue.idx == resnum and
system == self._last_residue.system):
lresname = self._last_residue.resname lresname = self._last_residue.resname
warnings.warn('Residue %d split into separate residues %s ' warnings.warn('Residue %d split into separate residues %s '
'and %s' % (resnum, lresname, resname), 'and %s' % (resnum, lresname, resname),
...@@ -1063,7 +1065,6 @@ class TrackedList(list): ...@@ -1063,7 +1065,6 @@ class TrackedList(list):
__delitem__ = _tracking(list.__delitem__) __delitem__ = _tracking(list.__delitem__)
append = _tracking(list.append) append = _tracking(list.append)
extend = _tracking(list.extend) extend = _tracking(list.extend)
__delslice__ = _tracking(list.__delslice__)
__setitem__ = _tracking(list.__setitem__) __setitem__ = _tracking(list.__setitem__)
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......
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