Context.cpp 10.6 KB
Newer Older
1
2
3
/* -------------------------------------------------------------------------- *
 *                                   OpenMM                                   *
 * -------------------------------------------------------------------------- *
Evan Pretti's avatar
Evan Pretti committed
4
5
 * This is part of the OpenMM molecular simulation toolkit.                   *
 * See https://openmm.org/development.                                        *
6
 *                                                                            *
7
 * Portions copyright (c) 2008-2024 Stanford University and the Authors.      *
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 * 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.                                     *
 * -------------------------------------------------------------------------- */

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

using namespace OpenMM;
using namespace std;

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

171
172
173
174
double Context::getTime() const {
    return impl->getTime();
}

175
void Context::setTime(double time) {
176
177
178
    impl->setTime(time);
}

179
180
181
182
183
184
185
186
long long Context::getStepCount() const {
    return impl->getStepCount();
}

void Context::setStepCount(long long count) {
    impl->setStepCount(count);
}

187
void Context::setPositions(const vector<Vec3>& positions) {
Peter Eastman's avatar
Peter Eastman committed
188
    if ((int) positions.size() != impl->getSystem().getNumParticles())
189
        throw OpenMMException("Called setPositions() on a Context with the wrong number of positions");
190
    impl->setPositions(positions);
191
192
}

193
void Context::setVelocities(const vector<Vec3>& velocities) {
Peter Eastman's avatar
Peter Eastman committed
194
    if ((int) velocities.size() != impl->getSystem().getNumParticles())
195
        throw OpenMMException("Called setVelocities() on a Context with the wrong number of velocities");
196
    impl->setVelocities(velocities);
197
198
}

199
void Context::setVelocitiesToTemperature(double temperature, int randomSeed) {
200
    const Integrator& integrator = impl->getIntegrator();
201
    const System& system = impl->getSystem();
202
203
204
205
206
207
208
209
210
211
212
213
214
    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);
215
216
217
    impl->applyVelocityConstraints(1e-5);
}

Peter Eastman's avatar
Peter Eastman committed
218
219
220
221
const map<string, double>& Context::getParameters() const {
    return impl->getParameters();
}

222
double Context::getParameter(const string& name) const {
223
224
225
    return impl->getParameter(name);
}

226
void Context::setParameter(const string& name, double value) {
227
228
229
    impl->setParameter(name, value);
}

230
231
void Context::setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c) {
    impl->setPeriodicBoxVectors(a, b, c);
232
233
}

234
235
236
237
void Context::applyConstraints(double tol) {
    impl->applyConstraints(tol);
}

238
239
240
241
void Context::applyVelocityConstraints(double tol) {
    impl->applyVelocityConstraints(tol);
}

242
243
244
245
void Context::computeVirtualSites() {
    impl->computeVirtualSites();
}

246
void Context::reinitialize(bool preserveState) {
247
    const System& system = impl->getSystem();
248
249
    Integrator& integrator = impl->getIntegrator();
    Platform& platform = impl->getPlatform();
250
251
252
    stringstream checkpoint(ios_base::out | ios_base::in | ios_base::binary);
    if (preserveState)
        createCheckpoint(checkpoint);
253
    bool hasSetPositions = impl->hasSetPositions;
254
    integrator.cleanup();
255
    delete impl;
256
    impl = new ContextImpl(*this, system, integrator, &platform, properties);
257
    impl->initialize();
258
    if (preserveState) {
259
        loadCheckpoint(checkpoint);
260
261
        impl->hasSetPositions = hasSetPositions;
    }
262
}
Peter Eastman's avatar
Peter Eastman committed
263
264
265
266
267
268
269
270

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

void Context::loadCheckpoint(istream& stream) {
    impl->loadCheckpoint(stream);
}
271
272
273
274

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

276
277
278
279
const ContextImpl& Context::getImpl() const {
    return *impl;
}

280
281
282
const vector<vector<int> >& Context::getMolecules() const {
    return impl->getMolecules();
}