void MonteCarloBarostatImpl::updateContextState(ContextImpl& context) { if (++step < owner.getFrequency() || owner.getFrequency() == 0) return; step = 0; // Compute the current potential energy. double initialEnergy = context.getOwner().getState(State::Energy).getPotentialEnergy(); // Modify the periodic box size. Vec3 box[3]; context.getPeriodicBoxVectors(box[0], box[1], box[2]); double volume = box[0][0]*box[1][1]*box[2][2]; double deltaVolume = volumeScale*2*(genrand_real2(random)-0.5); double newVolume = volume+deltaVolume; double lengthScale = std::pow(newVolume/volume, 1.0/3.0); kernel.getAs<ApplyMonteCarloBarostatKernel>().scaleCoordinates(context, lengthScale, lengthScale, lengthScale); context.getOwner().setPeriodicBoxVectors(box[0]*lengthScale, box[1]*lengthScale, box[2]*lengthScale); // Compute the energy of the modified system. double finalEnergy = context.getOwner().getState(State::Energy).getPotentialEnergy(); double pressure = context.getParameter(MonteCarloBarostat::Pressure())*(AVOGADRO*1e-25); double kT = BOLTZ*context.getParameter(MonteCarloBarostat::Temperature()); double w = finalEnergy-initialEnergy + pressure*deltaVolume - context.getMolecules().size()*kT*std::log(newVolume/volume); if (w > 0 && genrand_real2(random) > std::exp(-w/kT)) { // Reject the step. kernel.getAs<ApplyMonteCarloBarostatKernel>().restoreCoordinates(context); context.getOwner().setPeriodicBoxVectors(box[0], box[1], box[2]); volume = newVolume; } else numAccepted++; numAttempted++; if (numAttempted >= 10) { if (numAccepted < 0.25*numAttempted) { volumeScale /= 1.1; numAttempted = 0; numAccepted = 0; } else if (numAccepted > 0.75*numAttempted) { volumeScale = std::min(volumeScale*1.1, volume*0.3); numAttempted = 0; numAccepted = 0; } } }
double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { vector<RealVec>& posData = extractPositions(context); vector<RealVec>& forceData = extractForces(context); RealVec& box = extractBoxSize(context); float floatBoxSize[3] = {(float) box[0], (float) box[1], (float) box[2]}; double energy = 0; bool periodic = (nonbondedMethod == CutoffPeriodic); if (nonbondedMethod != NoCutoff) { neighborList->computeNeighborList(numParticles, data.posq, exclusions, floatBoxSize, data.isPeriodic, nonbondedCutoff, data.threads); nonbonded->setUseCutoff(nonbondedCutoff, *neighborList); } if (periodic) { double minAllowedSize = 2*nonbondedCutoff; if (box[0] < minAllowedSize || box[1] < minAllowedSize || box[2] < minAllowedSize) throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff."); nonbonded->setPeriodic(box); } bool globalParamsChanged = false; for (int i = 0; i < (int) globalParameterNames.size(); i++) { double value = context.getParameter(globalParameterNames[i]); if (globalParamValues[globalParameterNames[i]] != value) globalParamsChanged = true; globalParamValues[globalParameterNames[i]] = value; } if (useSwitchingFunction) nonbonded->setUseSwitchingFunction(switchingDistance); nonbonded->calculatePairIxn(numParticles, &data.posq[0], posData, particleParamArray, 0, globalParamValues, data.threadForce, includeForces, includeEnergy, energy); // Add in the long range correction. if (!hasInitializedLongRangeCorrection || (globalParamsChanged && forceCopy != NULL)) { longRangeCoefficient = CustomNonbondedForceImpl::calcLongRangeCorrection(*forceCopy, context.getOwner()); hasInitializedLongRangeCorrection = true; } energy += longRangeCoefficient/(box[0]*box[1]*box[2]); return energy; }
void MonteCarloAnisotropicBarostatImpl::updateContextState(ContextImpl& context) { if (++step < owner.getFrequency() || owner.getFrequency() == 0) return; if (!owner.getScaleX() && !owner.getScaleY() && !owner.getScaleZ()) return; step = 0; // Compute the current potential energy. double initialEnergy = context.getOwner().getState(State::Energy).getPotentialEnergy(); double pressure; // Choose which axis to modify at random. int axis; while (true) { double rnd = genrand_real2(random)*3.0; if (rnd < 1.0) { if (owner.getScaleX()) { axis = 0; pressure = context.getParameter(MonteCarloAnisotropicBarostat::PressureX())*(AVOGADRO*1e-25); break; } } else if (rnd < 2.0) { if (owner.getScaleY()) { axis = 1; pressure = context.getParameter(MonteCarloAnisotropicBarostat::PressureY())*(AVOGADRO*1e-25); break; } } else if (owner.getScaleZ()) { axis = 2; pressure = context.getParameter(MonteCarloAnisotropicBarostat::PressureZ())*(AVOGADRO*1e-25); break; } } // Modify the periodic box size. Vec3 box[3]; context.getPeriodicBoxVectors(box[0], box[1], box[2]); double volume = box[0][0]*box[1][1]*box[2][2]; double deltaVolume = volumeScale[axis]*2*(genrand_real2(random)-0.5); double newVolume = volume+deltaVolume; Vec3 lengthScale(1.0, 1.0, 1.0); lengthScale[axis] = newVolume/volume; kernel.getAs<ApplyMonteCarloBarostatKernel>().scaleCoordinates(context, lengthScale[0], lengthScale[1], lengthScale[2]); context.getOwner().setPeriodicBoxVectors(box[0]*lengthScale[0], box[1]*lengthScale[1], box[2]*lengthScale[2]); // Compute the energy of the modified system. double finalEnergy = context.getOwner().getState(State::Energy).getPotentialEnergy(); double kT = BOLTZ*owner.getTemperature(); double w = finalEnergy-initialEnergy + pressure*deltaVolume - context.getMolecules().size()*kT*std::log(newVolume/volume); if (w > 0 && genrand_real2(random) > std::exp(-w/kT)) { // Reject the step. kernel.getAs<ApplyMonteCarloBarostatKernel>().restoreCoordinates(context); context.getOwner().setPeriodicBoxVectors(box[0], box[1], box[2]); volume = newVolume; } else numAccepted[axis]++; numAttempted[axis]++; if (numAttempted[axis] >= 10) { if (numAccepted[axis] < 0.25*numAttempted[axis]) { volumeScale[axis] /= 1.1; numAttempted[axis] = 0; numAccepted[axis] = 0; } else if (numAccepted[axis] > 0.75*numAttempted[axis]) { volumeScale[axis] = std::min(volumeScale[axis]*1.1, volume*0.3); numAttempted[axis] = 0; numAccepted[axis] = 0; } } }