ReferenceLincsAlgorithm.cpp 10.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* Portions copyright (c) 2006-2009 Stanford University and Simbios.
 * Contributors: Pande Group
 *
 * 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 <string.h>
#include <sstream>

27
#include "SimTKOpenMMUtilities.h"
28
29
#include "ReferenceLincsAlgorithm.h"
#include "ReferenceDynamics.h"
30
#include "openmm/OpenMMException.h"
31
32

using std::vector;
33
using namespace OpenMM;
34
35
36
37
38
39
40
41
42
43
44

/**---------------------------------------------------------------------------------------

   ReferenceLincsAlgorithm constructor

   @param numberOfConstraints      number of constraints
   @param atomIndices              block of atom indices
   @param distance                 distances for constraints

   --------------------------------------------------------------------------------------- */

45
46
ReferenceLincsAlgorithm::ReferenceLincsAlgorithm(int numberOfConstraints,
                                                 int** atomIndices,
peastman's avatar
peastman committed
47
                                                 double* distance) {
48
49
50
51
52

   _numberOfConstraints        = numberOfConstraints;
   _atomIndices                = atomIndices;
   _distance                   = distance;

53
   _numTerms                   = 4;
54
55
56
57
58
59
60
61
62
63
64
   _hasInitialized             = false;
}

/**---------------------------------------------------------------------------------------

   Get number of constraints

   @return number of constraints

   --------------------------------------------------------------------------------------- */

65
int ReferenceLincsAlgorithm::getNumberOfConstraints() const {
66
67
68
69
70
71
72
73
74
75
76
   return _numberOfConstraints;
}

/**---------------------------------------------------------------------------------------

   Get the number of terms to use in the series expansion

   @return terms

   --------------------------------------------------------------------------------------- */

77
int ReferenceLincsAlgorithm::getNumTerms() const {
78
79
80
81
82
83
84
85
86
   return _numTerms;
}

/**---------------------------------------------------------------------------------------

   Set the number of terms to use in the series expansion

   --------------------------------------------------------------------------------------- */

87
void ReferenceLincsAlgorithm::setNumTerms(int terms) {
88
89
90
91
92
93
94
95
96
97
98
99
100
   _numTerms = terms;
}


/**---------------------------------------------------------------------------------------

   Initialize internal data structures.

   @param numberOfAtoms    number of atoms
   @param inverseMasses    1/mass

   --------------------------------------------------------------------------------------- */

peastman's avatar
peastman committed
101
void ReferenceLincsAlgorithm::initialize(int numberOfAtoms, vector<double>& inverseMasses) {
102
103
104
105
106
107
108
109
    _hasInitialized = true;
    vector<vector<int> > atomConstraints(numberOfAtoms);
    for (int constraint = 0; constraint < _numberOfConstraints; constraint++) {
        atomConstraints[_atomIndices[constraint][0]].push_back(constraint);
        atomConstraints[_atomIndices[constraint][1]].push_back(constraint);
    }
    _linkedConstraints.resize(_numberOfConstraints);
    for (int atom = 0; atom < numberOfAtoms; atom++) {
110
        for (int i = 0; i < (int)atomConstraints[atom].size(); i++)
111
112
113
114
115
116
117
118
119
            for (int j = 0; j < i; j++) {
                int c1 = atomConstraints[atom][i];
                int c2 = atomConstraints[atom][j];
                _linkedConstraints[c1].push_back(c2);
                _linkedConstraints[c2].push_back(c1);
            }
    }
    _sMatrix.resize(_numberOfConstraints);
    for (int constraint = 0; constraint < _numberOfConstraints; constraint++)
peastman's avatar
peastman committed
120
        _sMatrix[constraint] = 1.0/sqrt(inverseMasses[_atomIndices[constraint][0]]+inverseMasses[_atomIndices[constraint][1]]);
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
    _couplingMatrix.resize(_numberOfConstraints);
    for (int constraint = 0; constraint < _numberOfConstraints; constraint++)
        _couplingMatrix[constraint].resize(_linkedConstraints[constraint].size());
    _constraintDir.resize(_numberOfConstraints);
    _rhs1.resize(_numberOfConstraints);
    _rhs2.resize(_numberOfConstraints);
    _solution.resize(_numberOfConstraints);
}

/**---------------------------------------------------------------------------------------

 Solve the matrix equation

 --------------------------------------------------------------------------------------- */

void ReferenceLincsAlgorithm::solveMatrix() {
    for (int iteration = 0; iteration < _numTerms; iteration++) {
peastman's avatar
peastman committed
138
139
        vector<double>& rhs1 = (iteration%2 == 0 ? _rhs1 : _rhs2);
        vector<double>& rhs2 = (iteration%2 == 0 ? _rhs2 : _rhs1);
140
        for (int c1 = 0; c1 < _numberOfConstraints; c1++) {
peastman's avatar
peastman committed
141
            rhs2[c1] = 0.0;
142
            for (int j = 0; j < (int)_linkedConstraints[c1].size(); j++) {
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
                int c2 = _linkedConstraints[c1][j];
                rhs2[c1] += _couplingMatrix[c1][j]*rhs1[c2];
            }
            _solution[c1] += rhs2[c1];
        }
    }
}

/**---------------------------------------------------------------------------------------

 Update the atom position based on the solution to the matrix equation.

 @param numberOfAtoms    number of atoms
 @param atomCoordinates  atom coordinates
 @param inverseMasses    1/mass

 --------------------------------------------------------------------------------------- */

peastman's avatar
peastman committed
161
void ReferenceLincsAlgorithm::updateAtomPositions(int numberOfAtoms, vector<Vec3>& atomCoordinates, vector<double>& inverseMasses) {
162
    for (int i = 0; i < _numberOfConstraints; i++) {
peastman's avatar
peastman committed
163
        Vec3 delta(_sMatrix[i]*_solution[i]*_constraintDir[i][0],
164
165
166
167
                   _sMatrix[i]*_solution[i]*_constraintDir[i][1],
                   _sMatrix[i]*_solution[i]*_constraintDir[i][2]);
        int atom1 = _atomIndices[i][0];
        int atom2 = _atomIndices[i][1];
peastman's avatar
peastman committed
168
169
170
171
172
173
        atomCoordinates[atom1][0] -= inverseMasses[atom1]*delta[0];
        atomCoordinates[atom1][1] -= inverseMasses[atom1]*delta[1];
        atomCoordinates[atom1][2] -= inverseMasses[atom1]*delta[2];
        atomCoordinates[atom2][0] += inverseMasses[atom2]*delta[0];
        atomCoordinates[atom2][1] += inverseMasses[atom2]*delta[1];
        atomCoordinates[atom2][2] += inverseMasses[atom2]*delta[2];
174
175
176
177
178
179
180
181
182
183
184
185
186
187
    }
}

/**---------------------------------------------------------------------------------------

   Apply Lincs algorithm

   @param numberOfAtoms    number of atoms
   @param atomCoordinates  atom coordinates
   @param atomCoordinatesP atom coordinates prime
   @param inverseMasses    1/mass

   --------------------------------------------------------------------------------------- */

peastman's avatar
peastman committed
188
189
190
void ReferenceLincsAlgorithm::apply(int numberOfAtoms, vector<Vec3>& atomCoordinates,
                                         vector<Vec3>& atomCoordinatesP,
                                         vector<double>& inverseMasses) {
191
192

   if (_numberOfConstraints == 0)
193
       return;
194

195
   if (!_hasInitialized)
196
197
198
199
200
201
202
       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];
peastman's avatar
peastman committed
203
       _constraintDir[i] = Vec3(atomCoordinatesP[atom1][0]-atomCoordinatesP[atom2][0],
204
205
                                atomCoordinatesP[atom1][1]-atomCoordinatesP[atom2][1],
                                atomCoordinatesP[atom1][2]-atomCoordinatesP[atom2][2]);
peastman's avatar
peastman committed
206
       double invLength = 1/sqrt(_constraintDir[i].dot(_constraintDir[i]));
207
208
209
       _constraintDir[i][0] *= invLength;
       _constraintDir[i][1] *= invLength;
       _constraintDir[i][2] *= invLength;
peastman's avatar
peastman committed
210
       _rhs1[i] = _solution[i] = _sMatrix[i]*(1.0/invLength-_distance[i]);
211
212
213
214
   }

   // Build the coupling matrix.

215
   for (int c1 = 0; c1 < (int)_couplingMatrix.size(); c1++) {
peastman's avatar
peastman committed
216
       Vec3& dir1 = _constraintDir[c1];
217
       for (int j = 0; j < (int)_couplingMatrix[c1].size(); j++) {
218
           int c2 = _linkedConstraints[c1][j];
peastman's avatar
peastman committed
219
           Vec3& dir2 = _constraintDir[c2];
220
           if (_atomIndices[c1][0] == _atomIndices[c2][0] || _atomIndices[c1][1] == _atomIndices[c2][1])
peastman's avatar
peastman committed
221
               _couplingMatrix[c1][j] = -inverseMasses[_atomIndices[c1][0]]*_sMatrix[c1]*dir1.dot(dir2)*_sMatrix[c2];
222
           else
peastman's avatar
peastman committed
223
               _couplingMatrix[c1][j] = inverseMasses[_atomIndices[c1][1]]*_sMatrix[c1]*dir1.dot(dir2)*_sMatrix[c2];
224
225
226
227
228
229
230
231
232
233
234
235
236
       }
   }

   // 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];
peastman's avatar
peastman committed
237
       Vec3 delta(atomCoordinatesP[atom1][0]-atomCoordinatesP[atom2][0],
238
239
                  atomCoordinatesP[atom1][1]-atomCoordinatesP[atom2][1],
                  atomCoordinatesP[atom1][2]-atomCoordinatesP[atom2][2]);
peastman's avatar
peastman committed
240
241
242
243
       double p2 = 2.0*_distance[i]*_distance[i]-delta.dot(delta);
       if (p2 < 0.0)
           p2 = 0.0;
       _rhs1[i] = _solution[i] = _sMatrix[i]*(_distance[i]-sqrt(p2));
244
245
246
247
248
   }
   solveMatrix();
   updateAtomPositions(numberOfAtoms, atomCoordinatesP, inverseMasses);
}

249
250
251
252
253
254
255
256
257
258
259
/**---------------------------------------------------------------------------------------

   Apply constraint algorithm to velocities.

   @param numberOfAtoms    number of atoms
   @param atomCoordinates  atom coordinates
   @param velocities       atom velocities
   @param inverseMasses    1/mass

   --------------------------------------------------------------------------------------- */

peastman's avatar
peastman committed
260
261
void ReferenceLincsAlgorithm::applyToVelocities(int numberOfAtoms, std::vector<OpenMM::Vec3>& atomCoordinates,
               std::vector<OpenMM::Vec3>& velocities, std::vector<double>& inverseMasses) {
262
263
    throw OpenMM::OpenMMException("applyToVelocities is not implemented");
}