@@ -21,68 +21,85 @@ using namespace CustomCPPForces;
21
21
using namespace OpenMM ;
22
22
using namespace std ;
23
23
24
- void ConcertedRMSDForceImpl::initialize (ContextImpl& context) {
25
- CustomCPPForceImpl::initialize (context);
26
24
25
+ void ConcertedRMSDForceImpl::updateParameters (int systemSize) {
27
26
// Check for errors in the specification of particles.
28
- const System& system = context.getSystem ();
29
- int systemSize = system.getNumParticles ();
30
27
if (owner.getReferencePositions ().size () != systemSize)
31
28
throw OpenMMException (
32
- " RMSDForce : Number of reference positions does not equal number of particles in the System"
29
+ " ConcertedRMSDForce : Number of reference positions does not equal number of particles in the System"
33
30
);
34
31
35
- particles = owner.getParticles ();
36
- numParticles = particles.size ();
32
+ int numGroups = owner.getNumGroups ();
33
+ if (numGroups == 0 )
34
+ throw OpenMMException (" ConcertedRMSDForce: No particle groups have been specified" );
35
+
36
+ groups.resize (numGroups);
37
+ for (int i = 0 ; i < numGroups; i++) {
38
+ groups[i] = owner.getGroup (i);
39
+ if (groups[i].size () == 0 ) {
40
+ groups[i].resize (systemSize);
41
+ for (int j = 0 ; j < systemSize; j++)
42
+ groups[i][j] = j;
43
+ }
44
+ }
37
45
38
46
set<int > distinctParticles;
39
- for (int i : particles) {
40
- if (i < 0 || i >= systemSize) {
41
- stringstream msg;
42
- msg << " ConcertedRMSDForce: Illegal particle index for RMSD: " ;
43
- msg << i;
44
- throw OpenMMException (msg.str ());
45
- }
46
- if (distinctParticles.find (i) != distinctParticles.end ()) {
47
- stringstream msg;
48
- msg << " ConcertedRMSDForce: Duplicated particle index for RMSD: " ;
49
- msg << i;
50
- throw OpenMMException (msg.str ());
47
+ for (int k = 0 ; k < numGroups; k++)
48
+ for (int i : groups[k]) {
49
+ if (i < 0 || i >= systemSize) {
50
+ stringstream msg;
51
+ msg << " ConcertedRMSDForce: Illegal particle index " << i << " in group " << k;
52
+ throw OpenMMException (msg.str ());
53
+ }
54
+ if (distinctParticles.find (i) != distinctParticles.end ()) {
55
+ stringstream msg;
56
+ msg << " ConcertedRMSDForce: Duplicated particle index " << i << " in group " << k;
57
+ throw OpenMMException (msg.str ());
58
+ }
59
+ distinctParticles.insert (i);
51
60
}
52
- distinctParticles.insert (i);
61
+
62
+ referencePos.resize (0 );
63
+ const vector<Vec3>& positions = owner.getReferencePositions ();
64
+ for (auto & group : groups) {
65
+ Vec3 center (0.0 , 0.0 , 0.0 );
66
+ for (int i : group)
67
+ center += positions[i];
68
+ center /= group.size ();
69
+ for (int i : group)
70
+ referencePos.push_back (positions[i] - center);
53
71
}
72
+ }
54
73
55
- referencePos = owner.getReferencePositions ();
56
- Vec3 center (0.0 , 0.0 , 0.0 );
57
- for (int i : particles)
58
- center += referencePos[i];
59
- center /= numParticles;
60
- for (Vec3& p : referencePos)
61
- p -= center;
74
+ void ConcertedRMSDForceImpl::initialize (ContextImpl& context) {
75
+ CustomCPPForceImpl::initialize (context);
76
+ updateParameters (context.getSystem ().getNumParticles ());
62
77
}
63
78
64
79
double ConcertedRMSDForceImpl::computeForce (ContextImpl& context, const vector<Vec3>& positions, vector<Vec3>& forces) {
65
80
// Compute the RMSD and its gradient using the algorithm described in Coutsias et al,
66
81
// "Using quaternions to calculate RMSD" (doi: 10.1002/jcc.20110). First subtract
67
82
// the centroid from the atom positions. The reference positions have already been centered.
68
83
69
- Vec3 center (0.0 , 0.0 , 0.0 );
70
- for (int i : particles)
71
- center += positions[i];
72
- center /= numParticles;
84
+ int numParticles = referencePos.size ();
73
85
vector<Vec3> centeredPos (numParticles);
74
- for (int i = 0 ; i < numParticles; i++)
75
- centeredPos[i] = positions[particles[i]] - center;
86
+ int index = 0 ;
87
+ for (auto & group : groups) {
88
+ Vec3 center (0.0 , 0.0 , 0.0 );
89
+ for (int i : group)
90
+ center += positions[i];
91
+ center /= group.size ();
92
+ for (int i : group)
93
+ centeredPos[index++] = positions[i] - center;
94
+ }
76
95
77
96
// Compute the correlation matrix.
78
97
79
98
double R[3 ][3 ] = {{0 , 0 , 0 }, {0 , 0 , 0 }, {0 , 0 , 0 }};
80
99
for (int i = 0 ; i < 3 ; i++)
81
100
for (int j = 0 ; j < 3 ; j++)
82
- for (int k = 0 ; k < numParticles; k++) {
83
- int index = particles[k];
84
- R[i][j] += centeredPos[k][i]*referencePos[index][j];
85
- }
101
+ for (int index = 0 ; index < numParticles; index++)
102
+ R[i][j] += centeredPos[index][i]*referencePos[index][j];
86
103
87
104
// Compute the F matrix.
88
105
@@ -118,10 +135,10 @@ double ConcertedRMSDForceImpl::computeForce(ContextImpl& context, const vector<V
118
135
// Compute the RMSD.
119
136
120
137
double sum = 0.0 ;
121
- for (int i = 0 ; i < numParticles; i++) {
122
- int index = particles[i];
123
- sum += centeredPos[i ].dot (centeredPos[i ]) + referencePos[index].dot (referencePos[index]);
124
- }
138
+ for (auto & group : groups)
139
+ for ( int index = 0 ; index < group. size (); index++)
140
+ sum += centeredPos[index ].dot (centeredPos[index ]) + referencePos[index].dot (referencePos[index]);
141
+
125
142
double msd = (sum - 2 *values[3 ])/numParticles;
126
143
if (msd < 1e-20 ) {
127
144
// The particles are perfectly aligned, so all the forces should be zero.
@@ -143,30 +160,20 @@ double ConcertedRMSDForceImpl::computeForce(ContextImpl& context, const vector<V
143
160
144
161
// Rotate the reference positions and compute the forces.
145
162
146
- for (int i = 0 ; i < numParticles; i++) {
147
- const Vec3& p = referencePos[particles[i]];
148
- Vec3 rotatedRef (U[0 ][0 ]*p[0 ] + U[1 ][0 ]*p[1 ] + U[2 ][0 ]*p[2 ],
149
- U[0 ][1 ]*p[0 ] + U[1 ][1 ]*p[1 ] + U[2 ][1 ]*p[2 ],
150
- U[0 ][2 ]*p[0 ] + U[1 ][2 ]*p[1 ] + U[2 ][2 ]*p[2 ]);
151
- forces[particles[i]] = -(centeredPos[i] - rotatedRef) / (rmsd*numParticles);
163
+ index = 0 ;
164
+ for (auto & group : groups)
165
+ for (int i : group) {
166
+ const Vec3& p = referencePos[index];
167
+ Vec3 rotatedRef (U[0 ][0 ]*p[0 ] + U[1 ][0 ]*p[1 ] + U[2 ][0 ]*p[2 ],
168
+ U[0 ][1 ]*p[0 ] + U[1 ][1 ]*p[1 ] + U[2 ][1 ]*p[2 ],
169
+ U[0 ][2 ]*p[0 ] + U[1 ][2 ]*p[1 ] + U[2 ][2 ]*p[2 ]);
170
+ forces[i] = -(centeredPos[index] - rotatedRef) / (rmsd*groups[0 ].size ());
171
+ index++;
152
172
}
153
173
return rmsd;
154
174
}
155
175
156
176
void ConcertedRMSDForceImpl::updateParametersInContext (ContextImpl& context) {
157
- if (referencePos.size () != owner.getReferencePositions ().size ())
158
- throw OpenMMException (" updateParametersInContext: The number of reference positions has changed" );
159
- particles = owner.getParticles ();
160
- if (particles.size () == 0 )
161
- for (int i = 0 ; i < referencePos.size (); i++)
162
- particles.push_back (i);
163
- numParticles = particles.size ();
164
- referencePos = owner.getReferencePositions ();
165
- Vec3 center (0.0 , 0.0 , 0.0 );
166
- for (int i : particles)
167
- center += referencePos[i];
168
- center /= numParticles;
169
- for (Vec3& p : referencePos)
170
- p -= center;
177
+ updateParameters (context.getSystem ().getNumParticles ());
171
178
context.systemChanged ();
172
179
}
0 commit comments