Context.cpp 10.3 KB
Newer Older
1
2
3
4
5
6
7
8
/* -------------------------------------------------------------------------- *
 *                                   OpenMM                                   *
 * -------------------------------------------------------------------------- *
 * This is part of the OpenMM molecular simulation toolkit originating from   *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org.               *
 *                                                                            *
9
 * Portions copyright (c) 2008-2016 Stanford University and the Authors.      *
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 * 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.                                     *
 * -------------------------------------------------------------------------- */

32
33
#include "openmm/Context.h"
#include "openmm/internal/ContextImpl.h"
34
#include "openmm/OpenMMException.h"
35
#include "openmm/internal/ForceImpl.h"
36
#include <cmath>
37
38
#include <iostream>
#include <sstream>
39
40
41
42

using namespace OpenMM;
using namespace std;

43
44
45
46
47
48
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();
}

49
Context::Context(const System& system, Integrator& integrator) : properties(map<string, string>()) {
50
    impl = new ContextImpl(*this, system, integrator, 0, properties);
51
    impl->initialize();
52
53
}

54
Context::Context(const System& system, Integrator& integrator, Platform& platform) : properties(map<string, string>()) {
55
    impl = new ContextImpl(*this, system, integrator, &platform, properties);
56
    impl->initialize();
57
58
}

59
Context::Context(const System& system, Integrator& integrator, Platform& platform, const map<string, string>& properties) : properties(properties) {
60
    impl = new ContextImpl(*this, system, integrator, &platform, properties);
61
    impl->initialize();
62
63
}

64
Context::~Context() {
Lee-Ping's avatar
Lee-Ping committed
65
    delete impl;
66
67
}

68
const System& Context::getSystem() const {
69
70
71
72
    return impl->getSystem();

}

73
const Integrator& Context::getIntegrator() const {
74
75
76
    return impl->getIntegrator();
}

77
Integrator& Context::getIntegrator() {
78
    return impl->getIntegrator();
79
80
}

81
const Platform& Context::getPlatform() const {
82
83
    return impl->getPlatform();
}
84

85
Platform& Context::getPlatform() {
86
    return impl->getPlatform();
87
88
}

89
State Context::getState(int types, bool enforcePeriodicBox, int groups) const {
90
    State::StateBuilder builder(impl->getTime());
91
92
    Vec3 periodicBoxSize[3];
    impl->getPeriodicBoxVectors(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2]);
93
    builder.setPeriodicBoxVectors(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2]);
94
95
    bool includeForces = types&State::Forces;
    bool includeEnergy = types&State::Energy;
96
    bool includeParameterDerivs = types&State::ParameterDerivatives;
97
    bool needForcesForEnergy = (includeEnergy && getIntegrator().kineticEnergyRequiresForce());
98
    if (includeForces || includeEnergy || includeParameterDerivs) {
99
        double energy = impl->calcForcesAndEnergy(includeForces || needForcesForEnergy || includeParameterDerivs, includeEnergy, groups);
100
        if (includeEnergy)
101
102
103
104
105
106
            builder.setEnergy(impl->calcKineticEnergy(), energy);
        if (includeForces) {
            vector<Vec3> forces;
            impl->getForces(forces);
            builder.setForces(forces);
        }
107
    }
108
    if (types&State::Parameters) {
109
        map<string, double> params;
peastman's avatar
peastman committed
110
111
        for (auto& param : impl->parameters)
            params[param.first] = param.second;
112
        builder.setParameters(params);
113
    }
114
115
116
117
118
    if (types&State::ParameterDerivatives) {
        map<string, double> derivs;
        impl->getEnergyParameterDerivatives(derivs);
        builder.setEnergyParameterDerivatives(derivs);
    }
119
    if (types&State::Positions) {
120
121
        vector<Vec3> positions;
        impl->getPositions(positions);
122
123
        if (enforcePeriodicBox) {
            const vector<vector<int> >& molecules = impl->getMolecules();
peastman's avatar
peastman committed
124
            for (auto& mol : molecules) {
125
126
127
                // Find the molecule center.

                Vec3 center;
peastman's avatar
peastman committed
128
129
130
                for (int j : mol)
                    center += positions[j];
                center *= 1.0/mol.size();
131
132

                // Find the displacement to move it into the first periodic box.
133
                Vec3 diff;
134
135
136
                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]);
137
138

                // Translate all the particles in the molecule.
peastman's avatar
peastman committed
139
140
                for (int j : mol)
                    positions[j] -= diff;
141
142
            }
        }
143
144
145
146
147
148
        builder.setPositions(positions);
    }
    if (types&State::Velocities) {
        vector<Vec3> velocities;
        impl->getVelocities(velocities);
        builder.setVelocities(velocities);
149
    }
150
151
152
    if (types&State::IntegratorParameters) {
        getIntegrator().serializeParameters(builder.updateIntegratorParameters());
    }
153
    return builder.getState();
154
155
}

Peter Eastman's avatar
Peter Eastman committed
156
157
158
159
160
void Context::setState(const State& state) {
    setTime(state.getTime());
    Vec3 a, b, c;
    state.getPeriodicBoxVectors(a, b, c);
    setPeriodicBoxVectors(a, b, c);
peastman's avatar
peastman committed
161
    if ((state.getDataTypes()&State::Positions) != 0)
Peter Eastman's avatar
Peter Eastman committed
162
        setPositions(state.getPositions());
peastman's avatar
peastman committed
163
    if ((state.getDataTypes()&State::Velocities) != 0)
Peter Eastman's avatar
Peter Eastman committed
164
        setVelocities(state.getVelocities());
peastman's avatar
peastman committed
165
    if ((state.getDataTypes()&State::Parameters) != 0)
peastman's avatar
peastman committed
166
167
        for (auto& param : state.getParameters())
            setParameter(param.first, param.second);
168
169
    if ((state.getDataTypes()&State::IntegratorParameters) != 0)
        getIntegrator().deserializeParameters(state.getIntegratorParameters());
Peter Eastman's avatar
Peter Eastman committed
170
171
}

172
void Context::setTime(double time) {
173
174
175
    impl->setTime(time);
}

176
void Context::setPositions(const vector<Vec3>& positions) {
Peter Eastman's avatar
Peter Eastman committed
177
    if ((int) positions.size() != impl->getSystem().getNumParticles())
178
        throw OpenMMException("Called setPositions() on a Context with the wrong number of positions");
179
    impl->setPositions(positions);
180
181
}

182
void Context::setVelocities(const vector<Vec3>& velocities) {
Peter Eastman's avatar
Peter Eastman committed
183
    if ((int) velocities.size() != impl->getSystem().getNumParticles())
184
        throw OpenMMException("Called setVelocities() on a Context with the wrong number of velocities");
185
    impl->setVelocities(velocities);
186
187
}

188
void Context::setVelocitiesToTemperature(double temperature, int randomSeed) {
189
    const Integrator& integrator = impl->getIntegrator();
190
    const System& system = impl->getSystem();
191
192
193
194
195
196
197
198
199
200
201
202
203
    vector<Vec3> velocities = integrator.getVelocitiesForTemperature(system, temperature, randomSeed);
    double offset = integrator.getVelocityTimeOffset();
    if (offset != 0.0) {
        impl->calcForcesAndEnergy(true, false, -1);
        vector<Vec3> 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);
204
205
206
    impl->applyVelocityConstraints(1e-5);
}

Peter Eastman's avatar
Peter Eastman committed
207
208
209
210
const map<string, double>& Context::getParameters() const {
    return impl->getParameters();
}

211
double Context::getParameter(const string& name) const {
212
213
214
    return impl->getParameter(name);
}

215
void Context::setParameter(const string& name, double value) {
216
217
218
    impl->setParameter(name, value);
}

219
220
void Context::setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c) {
    impl->setPeriodicBoxVectors(a, b, c);
221
222
}

223
224
225
226
void Context::applyConstraints(double tol) {
    impl->applyConstraints(tol);
}

227
228
229
230
void Context::applyVelocityConstraints(double tol) {
    impl->applyVelocityConstraints(tol);
}

231
232
233
234
void Context::computeVirtualSites() {
    impl->computeVirtualSites();
}

235
void Context::reinitialize(bool preserveState) {
236
    const System& system = impl->getSystem();
237
238
    Integrator& integrator = impl->getIntegrator();
    Platform& platform = impl->getPlatform();
239
240
241
    stringstream checkpoint(ios_base::out | ios_base::in | ios_base::binary);
    if (preserveState)
        createCheckpoint(checkpoint);
242
    integrator.cleanup();
243
    delete impl;
244
    impl = new ContextImpl(*this, system, integrator, &platform, properties);
245
    impl->initialize();
246
247
    if (preserveState)
        loadCheckpoint(checkpoint);
248
}
Peter Eastman's avatar
Peter Eastman committed
249
250
251
252
253
254
255
256

void Context::createCheckpoint(ostream& stream) {
    impl->createCheckpoint(stream);
}

void Context::loadCheckpoint(istream& stream) {
    impl->loadCheckpoint(stream);
}
257
258
259
260

ContextImpl& Context::getImpl() {
    return *impl;
}
261

262
263
264
265
const ContextImpl& Context::getImpl() const {
    return *impl;
}

266
267
268
const vector<vector<int> >& Context::getMolecules() const {
    return impl->getMolecules();
}