ReferenceCustomCompoundBondIxn.cpp 12.7 KB
Newer Older
1

2
/* Portions copyright (c) 2009-2016 Stanford University and Simbios.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 * Contributors: Peter Eastman
 *
 * 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>
#include <utility>

29
#include "SimTKOpenMMUtilities.h"
30
31
32
33
34
35
36
37
#include "ReferenceForce.h"
#include "ReferenceCustomCompoundBondIxn.h"

using std::map;
using std::pair;
using std::string;
using std::stringstream;
using std::vector;
38
using namespace OpenMM;
39
40
41
42
43
44
45
46
47

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

   ReferenceCustomCompoundBondIxn constructor

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

ReferenceCustomCompoundBondIxn::ReferenceCustomCompoundBondIxn(int numParticlesPerBond, const vector<vector<int> >& bondAtoms,
            const Lepton::ParsedExpression& energyExpression, const vector<string>& bondParameterNames,
48
49
50
51
52
53
54
            const map<string, vector<int> >& distances, const map<string, vector<int> >& angles, const map<string, vector<int> >& dihedrals,
            const std::vector<Lepton::CompiledExpression> energyParamDerivExpressions) :
            bondAtoms(bondAtoms), energyExpression(energyExpression.createCompiledExpression()), usePeriodic(false),
            energyParamDerivExpressions(energyParamDerivExpressions) {
    expressionSet.registerExpression(this->energyExpression);
    for (int i = 0; i < this->energyParamDerivExpressions.size(); i++)
        expressionSet.registerExpression(this->energyParamDerivExpressions[i]);
55
56
57
58
59
    for (int i = 0; i < numParticlesPerBond; i++) {
        stringstream xname, yname, zname;
        xname << 'x' << (i+1);
        yname << 'y' << (i+1);
        zname << 'z' << (i+1);
60
61
62
        particleTerms.push_back(ReferenceCustomCompoundBondIxn::ParticleTermInfo(xname.str(), i, 0, energyExpression.differentiate(xname.str()).createCompiledExpression()));
        particleTerms.push_back(ReferenceCustomCompoundBondIxn::ParticleTermInfo(yname.str(), i, 1, energyExpression.differentiate(yname.str()).createCompiledExpression()));
        particleTerms.push_back(ReferenceCustomCompoundBondIxn::ParticleTermInfo(zname.str(), i, 2, energyExpression.differentiate(zname.str()).createCompiledExpression()));
63
    }
peastman's avatar
peastman committed
64
65
66
67
68
69
    for (auto& term : distances)
        distanceTerms.push_back(ReferenceCustomCompoundBondIxn::DistanceTermInfo(term.first, term.second, energyExpression.differentiate(term.first).createCompiledExpression()));
    for (auto& term : angles)
        angleTerms.push_back(ReferenceCustomCompoundBondIxn::AngleTermInfo(term.first, term.second, energyExpression.differentiate(term.first).createCompiledExpression()));
    for (auto& term : dihedrals)
        dihedralTerms.push_back(ReferenceCustomCompoundBondIxn::DihedralTermInfo(term.first, term.second, energyExpression.differentiate(term.first).createCompiledExpression()));
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    for (int i = 0; i < particleTerms.size(); i++) {
        expressionSet.registerExpression(particleTerms[i].forceExpression);
        particleTerms[i].index = expressionSet.getVariableIndex(particleTerms[i].name);
    }
    for (int i = 0; i < distanceTerms.size(); i++) {
        expressionSet.registerExpression(distanceTerms[i].forceExpression);
        distanceTerms[i].index = expressionSet.getVariableIndex(distanceTerms[i].name);
    }
    for (int i = 0; i < angleTerms.size(); i++) {
        expressionSet.registerExpression(angleTerms[i].forceExpression);
        angleTerms[i].index = expressionSet.getVariableIndex(angleTerms[i].name);
    }
    for (int i = 0; i < dihedralTerms.size(); i++) {
        expressionSet.registerExpression(dihedralTerms[i].forceExpression);
        dihedralTerms[i].index = expressionSet.getVariableIndex(dihedralTerms[i].name);
    }
    numParameters = bondParameterNames.size();
    for (int i = 0; i < numParameters; i++)
        bondParamIndex.push_back(expressionSet.getVariableIndex(bondParameterNames[i]));
89
90
91
92
93
94
95
96
}

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

   ReferenceCustomCompoundBondIxn destructor

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

97
ReferenceCustomCompoundBondIxn::~ReferenceCustomCompoundBondIxn() {
98
99
}

peastman's avatar
peastman committed
100
void ReferenceCustomCompoundBondIxn::setPeriodic(OpenMM::Vec3* vectors) {
101
102
103
104
105
106
    usePeriodic = true;
    boxVectors[0] = vectors[0];
    boxVectors[1] = vectors[1];
    boxVectors[2] = vectors[2];
}

107
108
109
110
111
112
113
114
115
116
117
118
/**---------------------------------------------------------------------------------------

   Calculate custom hbond interaction

   @param atomCoordinates    atom coordinates
   @param bondParameters     bond parameters values       bondParameters[bondIndex][parameterIndex]
   @param globalParameters   the values of global parameters
   @param forces             force array (forces added)
   @param totalEnergy        total energy

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

119
void ReferenceCustomCompoundBondIxn::calculatePairIxn(vector<Vec3>& atomCoordinates, vector<vector<double> >& bondParameters,
peastman's avatar
peastman committed
120
121
                                             const map<string, double>& globalParameters, vector<Vec3>& forces,
                                             double* totalEnergy, double* energyParamDerivs) {
peastman's avatar
peastman committed
122
123
    for (auto& param : globalParameters)
        expressionSet.setVariable(expressionSet.getVariableIndex(param.first), param.second);
124
    int numBonds = bondAtoms.size();
125
    for (int bond = 0; bond < numBonds; bond++) {
126
127
128
        for (int i = 0; i < numParameters; i++)
            expressionSet.setVariable(bondParamIndex[i], bondParameters[bond][i]);
        calculateOneIxn(bond, atomCoordinates, forces, totalEnergy, energyParamDerivs);
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
    }
}

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

     Calculate interaction for one bond

     @param bond             the index of the bond
     @param atomCoordinates  atom coordinates
     @param forces           force array (forces added)
     @param energyByAtom     atom energy
     @param totalEnergy      total energy

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

peastman's avatar
peastman committed
144
145
void ReferenceCustomCompoundBondIxn::calculateOneIxn(int bond, vector<Vec3>& atomCoordinates,
                        vector<Vec3>& forces, double* totalEnergy, double* energyParamDerivs) {
146
147
    // Compute all of the variables the energy can depend on.

148
    const vector<int>& atoms = bondAtoms[bond];
peastman's avatar
peastman committed
149
    for (auto& term : particleTerms)
150
        expressionSet.setVariable(term.index, atomCoordinates[atoms[term.atom]][term.component]);
peastman's avatar
peastman committed
151
    for (auto& term : distanceTerms) {
152
        computeDelta(atoms[term.p1], atoms[term.p2], term.delta, atomCoordinates);
153
        expressionSet.setVariable(term.index, term.delta[ReferenceForce::RIndex]);
154
    }
peastman's avatar
peastman committed
155
    for (auto& term : angleTerms) {
156
157
        computeDelta(atoms[term.p1], atoms[term.p2], term.delta1, atomCoordinates);
        computeDelta(atoms[term.p3], atoms[term.p2], term.delta2, atomCoordinates);
158
        expressionSet.setVariable(term.index, computeAngle(term.delta1, term.delta2));
159
    }
peastman's avatar
peastman committed
160
    for (auto& term : dihedralTerms) {
161
162
163
        computeDelta(atoms[term.p2], atoms[term.p1], term.delta1, atomCoordinates);
        computeDelta(atoms[term.p2], atoms[term.p3], term.delta2, atomCoordinates);
        computeDelta(atoms[term.p4], atoms[term.p3], term.delta3, atomCoordinates);
peastman's avatar
peastman committed
164
165
        double dotDihedral, signOfDihedral;
        double* crossProduct[] = {term.cross1, term.cross2};
166
        expressionSet.setVariable(term.index,getDihedralAngleBetweenThreeVectors(term.delta1, term.delta2, term.delta3, crossProduct, &dotDihedral, term.delta1, &signOfDihedral, 1));
167
168
169
170
    }
    
    // Apply forces based on individual particle coordinates.
    
peastman's avatar
peastman committed
171
    for (auto& term : particleTerms)
172
        forces[atoms[term.atom]][term.component] -= term.forceExpression.evaluate();
173
174
175

    // Apply forces based on distances.

peastman's avatar
peastman committed
176
    for (auto& term : distanceTerms) {
peastman's avatar
peastman committed
177
        double dEdR = term.forceExpression.evaluate()/(term.delta[ReferenceForce::RIndex]);
178
        for (int i = 0; i < 3; i++) {
peastman's avatar
peastman committed
179
           double force  = -dEdR*term.delta[i];
180
181
182
183
184
185
186
           forces[atoms[term.p1]][i] -= force;
           forces[atoms[term.p2]][i] += force;
        }
    }

    // Apply forces based on angles.

peastman's avatar
peastman committed
187
    for (auto& term : angleTerms) {
peastman's avatar
peastman committed
188
189
        double dEdTheta = term.forceExpression.evaluate();
        double thetaCross[ReferenceForce::LastDeltaRIndex];
190
        SimTKOpenMMUtilities::crossProductVector3(term.delta1, term.delta2, thetaCross);
peastman's avatar
peastman committed
191
        double lengthThetaCross = sqrt(DOT3(thetaCross, thetaCross));
192
        if (lengthThetaCross < 1.0e-06)
peastman's avatar
peastman committed
193
194
195
196
            lengthThetaCross = 1.0e-06;
        double termA = dEdTheta/(term.delta1[ReferenceForce::R2Index]*lengthThetaCross);
        double termC = -dEdTheta/(term.delta2[ReferenceForce::R2Index]*lengthThetaCross);
        double deltaCrossP[3][3];
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
        SimTKOpenMMUtilities::crossProductVector3(term.delta1, thetaCross, deltaCrossP[0]);
        SimTKOpenMMUtilities::crossProductVector3(term.delta2, thetaCross, deltaCrossP[2]);
        for (int i = 0; i < 3; i++) {
            deltaCrossP[0][i] *= termA;
            deltaCrossP[2][i] *= termC;
            deltaCrossP[1][i] = -(deltaCrossP[0][i]+deltaCrossP[2][i]);
        }
        for (int i = 0; i < 3; i++) {
            forces[atoms[term.p1]][i] += deltaCrossP[0][i];
            forces[atoms[term.p2]][i] += deltaCrossP[1][i];
            forces[atoms[term.p3]][i] += deltaCrossP[2][i];
        }
    }

    // Apply forces based on dihedrals.

peastman's avatar
peastman committed
213
    for (auto& term : dihedralTerms) {
peastman's avatar
peastman committed
214
215
216
217
218
        double dEdTheta = term.forceExpression.evaluate();
        double internalF[4][3];
        double forceFactors[4];
        double normCross1 = DOT3(term.cross1, term.cross1);
        double normBC = term.delta2[ReferenceForce::RIndex];
219
        forceFactors[0] = (-dEdTheta*normBC)/normCross1;
peastman's avatar
peastman committed
220
221
222
223
224
225
        double normCross2 = DOT3(term.cross2, term.cross2);
        forceFactors[3] = (dEdTheta*normBC)/normCross2;
        forceFactors[1] = DOT3(term.delta1, term.delta2);
        forceFactors[1] /= term.delta2[ReferenceForce::R2Index];
        forceFactors[2] = DOT3(term.delta3, term.delta2);
        forceFactors[2] /= term.delta2[ReferenceForce::R2Index];
226
227
228
        for (int i = 0; i < 3; i++) {
            internalF[0][i] = forceFactors[0]*term.cross1[i];
            internalF[3][i] = forceFactors[3]*term.cross2[i];
peastman's avatar
peastman committed
229
            double s = forceFactors[1]*internalF[0][i] - forceFactors[2]*internalF[3][i];
230
231
232
233
234
235
236
237
238
239
240
241
242
243
            internalF[1][i] = internalF[0][i] - s;
            internalF[2][i] = internalF[3][i] + s;
        }
        for (int i = 0; i < 3; i++) {
            forces[atoms[term.p1]][i] += internalF[0][i];
            forces[atoms[term.p2]][i] -= internalF[1][i];
            forces[atoms[term.p3]][i] -= internalF[2][i];
            forces[atoms[term.p4]][i] += internalF[3][i];
        }
    }

    // Add the energy

    if (totalEnergy)
peastman's avatar
peastman committed
244
        *totalEnergy += energyExpression.evaluate();
245
246
247
248
249
    
    // Compute derivatives of the energy.
    
    for (int i = 0; i < energyParamDerivExpressions.size(); i++)
        energyParamDerivs[i] += energyParamDerivExpressions[i].evaluate();
250
251
}

peastman's avatar
peastman committed
252
void ReferenceCustomCompoundBondIxn::computeDelta(int atom1, int atom2, double* delta, vector<Vec3>& atomCoordinates) const {
253
254
255
256
    if (usePeriodic)
        ReferenceForce::getDeltaRPeriodic(atomCoordinates[atom1], atomCoordinates[atom2], boxVectors, delta);
    else
        ReferenceForce::getDeltaR(atomCoordinates[atom1], atomCoordinates[atom2], delta);
257
258
}

peastman's avatar
peastman committed
259
260
261
262
double ReferenceCustomCompoundBondIxn::computeAngle(double* vec1, double* vec2) {
    double dot = DOT3(vec1, vec2);
    double cosine = dot/sqrt((vec1[ReferenceForce::R2Index]*vec2[ReferenceForce::R2Index]));
    double angle;
263
264
265
266
267
    if (cosine >= 1)
        angle = 0;
    else if (cosine <= -1)
        angle = PI_M;
    else
peastman's avatar
peastman committed
268
        angle = acos(cosine);
269
270
    return angle;
}