/* -------------------------------------------------------------------------- * * OpenMM * * -------------------------------------------------------------------------- * * This is part of the OpenMM molecular simulation toolkit. * * See https://openmm.org/development. * * * * Portions copyright (c) 2008-2024 Stanford University and the Authors. * * Authors: Peter Eastman * * Contributors: * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * * USE OR OTHER DEALINGS IN THE SOFTWARE. * * -------------------------------------------------------------------------- */ #include "openmm/Context.h" #include "openmm/internal/ContextImpl.h" #include "openmm/OpenMMException.h" #include "openmm/internal/ForceImpl.h" #include #include #include using namespace OpenMM; using namespace std; Context::Context(const System& system, Integrator& integrator, ContextImpl& linked) : properties(linked.getOwner().properties) { // This is used by ContextImpl::createLinkedContext(). impl = new ContextImpl(*this, system, integrator, &linked.getPlatform(), properties, &linked); impl->initialize(); } Context::Context(const System& system, Integrator& integrator) : properties(map()) { impl = new ContextImpl(*this, system, integrator, 0, properties); impl->initialize(); } Context::Context(const System& system, Integrator& integrator, Platform& platform) : properties(map()) { impl = new ContextImpl(*this, system, integrator, &platform, properties); impl->initialize(); } Context::Context(const System& system, Integrator& integrator, Platform& platform, const map& properties) : properties(properties) { impl = new ContextImpl(*this, system, integrator, &platform, properties); impl->initialize(); } Context::~Context() { delete impl; } const System& Context::getSystem() const { return impl->getSystem(); } const Integrator& Context::getIntegrator() const { return impl->getIntegrator(); } Integrator& Context::getIntegrator() { return impl->getIntegrator(); } const Platform& Context::getPlatform() const { return impl->getPlatform(); } Platform& Context::getPlatform() { return impl->getPlatform(); } State Context::getState(int types, bool enforcePeriodicBox, int groups) const { State::StateBuilder builder(impl->getTime(), impl->getStepCount()); Vec3 periodicBoxSize[3]; impl->getPeriodicBoxVectors(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2]); builder.setPeriodicBoxVectors(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2]); bool includeForces = types&State::Forces; bool includeEnergy = types&State::Energy; bool includeParameterDerivs = types&State::ParameterDerivatives; bool needForcesForEnergy = (includeEnergy && getIntegrator().kineticEnergyRequiresForce()); if (includeForces || includeEnergy || includeParameterDerivs) { double energy = impl->calcForcesAndEnergy(includeForces || needForcesForEnergy || includeParameterDerivs, includeEnergy, groups); if (includeEnergy) builder.setEnergy(impl->calcKineticEnergy(), energy); if (includeForces) { vector forces; impl->getForces(forces); builder.setForces(forces); } } if (types&State::Parameters) { map params; for (auto& param : impl->parameters) params[param.first] = param.second; builder.setParameters(params); } if (types&State::ParameterDerivatives) { map derivs; impl->getEnergyParameterDerivatives(derivs); builder.setEnergyParameterDerivatives(derivs); } if (types&State::Positions) { vector positions; impl->getPositions(positions); if (enforcePeriodicBox) { const vector >& molecules = impl->getMolecules(); for (auto& mol : molecules) { // Find the molecule center. Vec3 center; for (int j : mol) center += positions[j]; center *= 1.0/mol.size(); // Find the displacement to move it into the first periodic box. Vec3 diff; diff += periodicBoxSize[2]*floor(center[2]/periodicBoxSize[2][2]); diff += periodicBoxSize[1]*floor((center[1]-diff[1])/periodicBoxSize[1][1]); diff += periodicBoxSize[0]*floor((center[0]-diff[0])/periodicBoxSize[0][0]); // Translate all the particles in the molecule. for (int j : mol) positions[j] -= diff; } } builder.setPositions(positions); } if (types&State::Velocities) { vector velocities; impl->getVelocities(velocities); builder.setVelocities(velocities); } if (types&State::IntegratorParameters) { getIntegrator().serializeParameters(builder.updateIntegratorParameters()); } return builder.getState(); } void Context::setState(const State& state) { setTime(state.getTime()); setStepCount(state.getStepCount()); Vec3 a, b, c; state.getPeriodicBoxVectors(a, b, c); setPeriodicBoxVectors(a, b, c); if ((state.getDataTypes()&State::Positions) != 0) setPositions(state.getPositions()); if ((state.getDataTypes()&State::Velocities) != 0) setVelocities(state.getVelocities()); if ((state.getDataTypes()&State::Parameters) != 0) for (auto& param : state.getParameters()) setParameter(param.first, param.second); if ((state.getDataTypes()&State::IntegratorParameters) != 0) getIntegrator().deserializeParameters(state.getIntegratorParameters()); } double Context::getTime() const { return impl->getTime(); } void Context::setTime(double time) { impl->setTime(time); } long long Context::getStepCount() const { return impl->getStepCount(); } void Context::setStepCount(long long count) { impl->setStepCount(count); } void Context::setPositions(const vector& positions) { if ((int) positions.size() != impl->getSystem().getNumParticles()) throw OpenMMException("Called setPositions() on a Context with the wrong number of positions"); impl->setPositions(positions); } void Context::setVelocities(const vector& velocities) { if ((int) velocities.size() != impl->getSystem().getNumParticles()) throw OpenMMException("Called setVelocities() on a Context with the wrong number of velocities"); impl->setVelocities(velocities); } void Context::setVelocitiesToTemperature(double temperature, int randomSeed) { const Integrator& integrator = impl->getIntegrator(); const System& system = impl->getSystem(); vector velocities = integrator.getVelocitiesForTemperature(system, temperature, randomSeed); double offset = integrator.getVelocityTimeOffset(); if (offset != 0.0) { impl->calcForcesAndEnergy(true, false, -1); vector forces; impl->getForces(forces); for (int i = 0; i < system.getNumParticles(); i++) { double mass = system.getParticleMass(i); if (mass != 0.0) velocities[i] -= (offset/mass)*forces[i]; } } setVelocities(velocities); impl->applyVelocityConstraints(1e-5); } const map& Context::getParameters() const { return impl->getParameters(); } double Context::getParameter(const string& name) const { return impl->getParameter(name); } void Context::setParameter(const string& name, double value) { impl->setParameter(name, value); } void Context::setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c) { impl->setPeriodicBoxVectors(a, b, c); } void Context::applyConstraints(double tol) { impl->applyConstraints(tol); } void Context::applyVelocityConstraints(double tol) { impl->applyVelocityConstraints(tol); } void Context::computeVirtualSites() { impl->computeVirtualSites(); } void Context::reinitialize(bool preserveState) { const System& system = impl->getSystem(); Integrator& integrator = impl->getIntegrator(); Platform& platform = impl->getPlatform(); stringstream checkpoint(ios_base::out | ios_base::in | ios_base::binary); if (preserveState) createCheckpoint(checkpoint); bool hasSetPositions = impl->hasSetPositions; integrator.cleanup(); delete impl; impl = new ContextImpl(*this, system, integrator, &platform, properties); impl->initialize(); if (preserveState) { loadCheckpoint(checkpoint); impl->hasSetPositions = hasSetPositions; } } void Context::createCheckpoint(ostream& stream) { impl->createCheckpoint(stream); } void Context::loadCheckpoint(istream& stream) { impl->loadCheckpoint(stream); } ContextImpl& Context::getImpl() { return *impl; } const ContextImpl& Context::getImpl() const { return *impl; } const vector >& Context::getMolecules() const { return impl->getMolecules(); }