int ReferenceLincsAlgorithm::apply( int numberOfAtoms, vector<RealVec>& atomCoordinates, vector<RealVec>& atomCoordinatesP, vector<RealOpenMM>& inverseMasses ){ // --------------------------------------------------------------------------------------- static const char* methodName = "\nReferenceLincsAlgorithm::apply"; static const RealOpenMM zero = 0.0; static const RealOpenMM one = 1.0; static const RealOpenMM two = 2.0; // --------------------------------------------------------------------------------------- if (_numberOfConstraints == 0) return SimTKOpenMMCommon::DefaultReturn; if( !_hasInitialized ) initialize(numberOfAtoms, inverseMasses); // Calculate the direction of each constraint, along with the initial RHS and solution vectors. for (int i = 0; i < _numberOfConstraints; i++) { int atom1 = _atomIndices[i][0]; int atom2 = _atomIndices[i][1]; _constraintDir[i] = RealVec(atomCoordinatesP[atom1][0]-atomCoordinatesP[atom2][0], atomCoordinatesP[atom1][1]-atomCoordinatesP[atom2][1], atomCoordinatesP[atom1][2]-atomCoordinatesP[atom2][2]); RealOpenMM invLength = (RealOpenMM)(1/SQRT((RealOpenMM)_constraintDir[i].dot(_constraintDir[i]))); _constraintDir[i][0] *= invLength; _constraintDir[i][1] *= invLength; _constraintDir[i][2] *= invLength; _rhs1[i] = _solution[i] = _sMatrix[i]*(one/invLength-_distance[i]); } // Build the coupling matrix. for (int c1 = 0; c1 < (int)_couplingMatrix.size(); c1++) { RealVec& dir1 = _constraintDir[c1]; for (int j = 0; j < (int)_couplingMatrix[c1].size(); j++) { int c2 = _linkedConstraints[c1][j]; RealVec& dir2 = _constraintDir[c2]; if (_atomIndices[c1][0] == _atomIndices[c2][0] || _atomIndices[c1][1] == _atomIndices[c2][1]) _couplingMatrix[c1][j] = (RealOpenMM)(-inverseMasses[_atomIndices[c1][0]]*_sMatrix[c1]*dir1.dot(dir2)*_sMatrix[c2]); else _couplingMatrix[c1][j] = (RealOpenMM)(inverseMasses[_atomIndices[c1][1]]*_sMatrix[c1]*dir1.dot(dir2)*_sMatrix[c2]); } } // Solve the matrix equation and update the positions. solveMatrix(); updateAtomPositions(numberOfAtoms, atomCoordinatesP, inverseMasses); // Correct for rotational lengthening. for (int i = 0; i < _numberOfConstraints; i++) { int atom1 = _atomIndices[i][0]; int atom2 = _atomIndices[i][1]; RealVec delta(atomCoordinatesP[atom1][0]-atomCoordinatesP[atom2][0], atomCoordinatesP[atom1][1]-atomCoordinatesP[atom2][1], atomCoordinatesP[atom1][2]-atomCoordinatesP[atom2][2]); RealOpenMM p2 = (RealOpenMM)(two*_distance[i]*_distance[i]-delta.dot(delta)); if (p2 < zero) p2 = zero; _rhs1[i] = _solution[i] = _sMatrix[i]*(_distance[i]-SQRT(p2)); } solveMatrix(); updateAtomPositions(numberOfAtoms, atomCoordinatesP, inverseMasses); return SimTKOpenMMCommon::DefaultReturn; }
// ----------------------------------------------------------------------------- // INITIALIZE OpenMM DATA STRUCTURES // ----------------------------------------------------------------------------- // We take these actions here: // (1) Load any available OpenMM plugins, e.g. Cuda and Brook. // (2) Allocate a MyOpenMMData structure to hang on to OpenMM data structures // in a manner which is opaque to the caller. // (3) Fill the OpenMM::System with the force field parameters we want to // use and the particular set of atoms to be simulated. // (4) Create an Integrator and a Context associating the Integrator with // the System. // (5) Select the OpenMM platform to be used. // (6) Return the MyOpenMMData struct and the name of the Platform in use. // // Note that this function must understand the calling MD code's molecule and // force field data structures so will need to be customized for each MD code. static MyOpenMMData* myInitializeOpenMM( int numWatersAlongEdge, double temperature, double frictionInPerPs, double stepSizeInFs, std::string& platformName) { // Load all available OpenMM plugins from their default location. OpenMM::Platform::loadPluginsFromDirectory (OpenMM::Platform::getDefaultPluginsDirectory()); // Allocate space to hold OpenMM objects while we're using them. MyOpenMMData* omm = new MyOpenMMData(); // Create a System and Force objects within the System. Retain a reference // to each force object so we can fill in the forces. Note: the System owns // the force objects and will take care of deleting them; don't do it yourself! OpenMM::System& system = *(omm->system = new OpenMM::System()); OpenMM::NonbondedForce& nonbond = *new OpenMM::NonbondedForce(); system.addForce(&nonbond); OpenMM::HarmonicBondForce& bondStretch = *new OpenMM::HarmonicBondForce(); system.addForce(&bondStretch); OpenMM::HarmonicAngleForce& bondBend = *new OpenMM::HarmonicAngleForce(); system.addForce(&bondBend); OpenMM::AndersenThermostat& thermostat = *new OpenMM::AndersenThermostat( temperature, // kelvins frictionInPerPs); // collision frequency in 1/picoseconds system.addForce(&thermostat); // Volume of one water is 30 Angstroms cubed; // Thus length in one dimension is cube-root of 30, // or 3.107 Angstroms or 0.3107 nanometers const double WaterSizeInNm = 0.3107; // edge of cube containing one water, in nanometers // Place water molecules one at a time in an NxNxN rectilinear grid const double boxEdgeLengthInNm = WaterSizeInNm * numWatersAlongEdge; // Create periodic box nonbond.setNonbondedMethod(OpenMM::NonbondedForce::PME); nonbond.setUseDispersionCorrection(true); nonbond.setCutoffDistance(CutoffDistanceInAng * OpenMM::NmPerAngstrom); nonbond.setSwitchingDistance(SwitchDistanceInAng * OpenMM::NmPerAngstrom); nonbond.setEwaldErrorTolerance(1e-6); system.setDefaultPeriodicBoxVectors(Vec3(boxEdgeLengthInNm,0,0), Vec3(0,boxEdgeLengthInNm,0), Vec3(0,0,boxEdgeLengthInNm)); // Specify the atoms and their properties: // (1) System needs to know the masses and constraints (if any). // (2) NonbondedForce needs charges,van der Waals properties (in MD units!). // (3) Collect starting positions for initializing the simulation later. // Create data structures to hold lists of initial positions and bonds std::vector<Vec3> initialPosInNm; std::vector< std::pair<int,int> > bondPairs; // Add water molecules one at a time in the NxNxN cubic lattice for (int latticeX = 0; latticeX < numWatersAlongEdge; ++latticeX) for (int latticeY = 0; latticeY < numWatersAlongEdge; ++latticeY) for (int latticeZ = 0; latticeZ < numWatersAlongEdge; ++latticeZ) { // Add parameters for one water molecule // Add atom masses to system int oIndex = system.addParticle(O_mass); // O int h1Index = system.addParticle(H_mass); // H1 int h2Index = system.addParticle(H_mass); // H2 // Add atom charge, sigma, and stiffness to nonbonded force nonbond.addParticle( // Oxygen O_charge, O_vdwRadInAng * OpenMM::NmPerAngstrom * OpenMM::SigmaPerVdwRadius, O_vdwEnergyInKcal * OpenMM::KJPerKcal); nonbond.addParticle( // Hydrogen1 H_charge, H_vdwRadInAng * OpenMM::NmPerAngstrom * OpenMM::SigmaPerVdwRadius, H_vdwEnergyInKcal * OpenMM::KJPerKcal); nonbond.addParticle( // Hydrogen2 H_charge, H_vdwRadInAng * OpenMM::NmPerAngstrom * OpenMM::SigmaPerVdwRadius, H_vdwEnergyInKcal * OpenMM::KJPerKcal); // Constrain O-H bond lengths or use harmonic forces. if (UseConstraints) { system.addConstraint(oIndex, h1Index, OH_nominalLengthInAng * OpenMM::NmPerAngstrom); system.addConstraint(oIndex, h2Index, OH_nominalLengthInAng * OpenMM::NmPerAngstrom); } else { // Add stretch parameters for two covalent bonds // Note factor of 2 for stiffness below because Amber specifies the constant // as it is used in the harmonic energy term kx^2 with force 2kx; OpenMM wants // it as used in the force term kx, with energy kx^2/2. bondStretch.addBond(oIndex, h1Index, OH_nominalLengthInAng * OpenMM::NmPerAngstrom, OH_stiffnessInKcalPerAng2 * 2 * OpenMM::KJPerKcal * OpenMM::AngstromsPerNm * OpenMM::AngstromsPerNm); bondStretch.addBond(oIndex, h2Index, OH_nominalLengthInAng * OpenMM::NmPerAngstrom, OH_stiffnessInKcalPerAng2 * 2 * OpenMM::KJPerKcal * OpenMM::AngstromsPerNm * OpenMM::AngstromsPerNm); } // Store bonds for exclusion list bondPairs.push_back(std::make_pair(oIndex, h1Index)); bondPairs.push_back(std::make_pair(oIndex, h2Index)); // Add bond bend parameters for one angle. // See note under bond stretch above regarding the factor of 2 here. bondBend.addAngle(h1Index, oIndex, h2Index, HOH_nominalAngleInDeg * OpenMM::RadiansPerDegree, HOH_stiffnessInKcalPerRad2 * 2 * OpenMM::KJPerKcal); // Location of this molecule in the lattice Vec3 latticeVec(WaterSizeInNm * latticeX, WaterSizeInNm * latticeY, WaterSizeInNm * latticeZ); // flip half the waters to prevent giant dipole int flip = (rand() % 100) > 49 ? 1 : -1; // place this water initialPosInNm.push_back(Vec3(0,0,0) + latticeVec); // O initialPosInNm.push_back(Vec3(0.09572*flip,0,0) + latticeVec); // H1 initialPosInNm.push_back(Vec3(-0.02397*flip,0.09267*flip,0) + latticeVec); // H2 } // Populate nonbonded exclusions nonbond.createExceptionsFromBonds(bondPairs, 1.0, 1.0); // Choose an Integrator for advancing time, and a Context connecting the // System with the Integrator for simulation. Let the Context choose the // best available Platform. Initialize the configuration from the default // positions we collected above. Initial velocities will be zero. omm->integrator = new OpenMM::VerletIntegrator(StepSizeInFs * OpenMM::PsPerFs); omm->context = new OpenMM::Context(*omm->system, *omm->integrator); omm->context->setPositions(initialPosInNm); platformName = omm->context->getPlatform().getName(); return omm; }
MBPolReferenceDispersionForce::MBPolReferenceDispersionForce( ) : _nonbondedMethod(NoCutoff), _cutoff(1.0e+10) { _periodicBoxDimensions = RealVec( 0.0, 0.0, 0.0 ); }