1
package org.openscience.cdk.modeling.forcefield;
3
import java.util.Hashtable;
4
import java.util.Vector;
6
import javax.vecmath.GMatrix;
7
import javax.vecmath.GVector;
9
import org.openscience.cdk.interfaces.IAtomContainer;
10
import org.openscience.cdk.interfaces.IBond;
11
import org.openscience.cdk.interfaces.IAtom;
12
import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;
13
import org.openscience.cdk.modeling.builder3d.MMFF94ParametersCall;
14
import org.openscience.cdk.qsar.IAtomicDescriptor;
15
import org.openscience.cdk.qsar.descriptors.atomic.PeriodicTablePositionDescriptor;
16
import org.openscience.cdk.qsar.result.IntegerResult;
17
import org.openscience.cdk.tools.LoggingTool;
20
* Stretch-Bend Interaction calculator for the potential energy function.
21
* Include function and derivatives.
24
*@cdk.created 2005-02-15
25
*@cdk.module forcefield
27
public class StretchBendInteractions {
29
String functionShape = " Stretch-Bend Interactions ";
31
double mmff94SumEBA = 0;
32
GVector gradientMMFF94SumEBA = null;
33
GVector order2ndErrorApproximateGradientMMFF94SumEBA = null;
34
GVector order5thErrorApproximateGradientMMFF94SumEBA = null;
35
GMatrix hessianMMFF94SumEBA = null;
36
GVector currentCoordinates = null;
37
GVector gradientCurrentCoordinates = null;
39
double[][] dDeltarij = null;
40
double[][] dDeltarkj = null;
41
double[][] dDeltav = null;
43
int[][] bondijAtomPosition = null;
44
int[][] bondkjAtomPosition = null;
47
double[] kbaIJK = null;
48
double[] kbaKJI = null;
51
double[] deltarij = null;
52
double[] deltarkj = null;
54
BondStretching bs = new BondStretching();
55
AngleBending ab = new AngleBending();
56
private LoggingTool logger;
58
GVector moleculeCurrentCoordinates = null;
59
boolean[] changeAtomCoordinates = null;
60
int changedCoordinates;
64
* Constructor for the StretchBendInteractions object
66
public StretchBendInteractions() {
67
logger = new LoggingTool(this);
72
* Set MMFF94 reference bond lengths r0IJ and r0JK and stretch-bend
73
* interaction constants kbaIJK and kbaKJI for each i-j-k angle in the
76
*@param molecule The molecule like an AtomContainer object.
77
*@param parameterSet MMFF94 parameters set
78
*@exception Exception Description of the Exception
80
public void setMMFF94StretchBendParameters(IAtomContainer molecule, Hashtable parameterSet, boolean angleBendingFlag) throws Exception {
82
//logger.debug("setMMFF94StretchBendParameters");
84
ab.setMMFF94AngleBendingParameters(molecule, parameterSet, angleBendingFlag);
86
IAtom[] atomConnected = null;
88
Vector stretchBendInteractionsData = null;
89
Vector bondData = null;
90
MMFF94ParametersCall pc = new MMFF94ParametersCall();
91
pc.initialize(parameterSet);
93
bondijAtomPosition = new int[ab.angleNumber][];
94
bondkjAtomPosition = new int[ab.angleNumber][];
95
r0IJ = new double[ab.angleNumber];
96
r0KJ = new double[ab.angleNumber];
97
kbaIJK = new double[ab.angleNumber];
98
kbaKJI = new double[ab.angleNumber];
108
IAtomicDescriptor descriptor = new PeriodicTablePositionDescriptor();
115
for (int j = 0; j < molecule.getAtomCount(); j++) {
117
atomConnected = AtomContainerManipulator.getAtomArray(molecule.getConnectedAtomsList(molecule.getAtom(j)));
119
if (atomConnected.length > 1) {
121
for (int i = 0; i < atomConnected.length; i++) {
123
for (int k = i + 1; k < atomConnected.length; k++) {
127
bondIJ = molecule.getBond(atomConnected[i], molecule.getAtom(j));
128
bondIJType = bondIJ.getProperty("MMFF94 bond type").toString();
130
bondKJ = molecule.getBond(atomConnected[k], molecule.getAtom(j));
131
bondKJType = bondKJ.getProperty("MMFF94 bond type").toString();
134
if ((bondIJType == "1") | (bondKJType == "1")) {
137
if ((bondIJType == "1") & (bondKJType == "1")) {
141
//logger.debug("bondIJType = " + bondIJType + ", bondKJType = " + bondKJType + ", angleType = " + angleType);
144
if ((angleType == "0") & (bondIJType == "0") & (bondKJType == "0")) {strbndType = "0";}
145
else if ((angleType == "1") & (bondIJType == "1") & (bondKJType == "0")) {strbndType = "1";}
146
else if ((angleType == "1") & (bondIJType == "0") & (bondKJType == "1")) {strbndType = "2";}
147
else if ((angleType == "2") & (bondIJType == "1") & (bondKJType == "1")) {strbndType = "3";}
148
else if ((angleType == "4") & (bondIJType == "0") & (bondKJType == "0")) {strbndType = "4";}
149
else if ((angleType == "3") & (bondIJType == "0") & (bondKJType == "0")) {strbndType = "5";}
150
else if ((angleType == "5") & (bondIJType == "1") & (bondKJType == "0")) {strbndType = "6";}
151
else if ((angleType == "5") & (bondIJType == "0") & (bondKJType == "1")) {strbndType = "7";}
152
else if ((angleType == "6") & (bondIJType == "1") & (bondKJType == "1")) {strbndType = "8";}
153
else if ((angleType == "7") & (bondIJType == "1") & (bondKJType == "0")) {strbndType = "9";}
154
else if ((angleType == "7") & (bondIJType == "0") & (bondKJType == "1")) {strbndType = "10";}
155
else if ((angleType == "8") & (bondIJType == "1") & (bondKJType == "1")) {strbndType = "11";}
157
//logger.debug("strbnd: " + strbndType + ", " + atomConnected[i].getAtomTypeName() + "(" + molecule.getAtomNumber(atomConnected[i]) + "), " + molecule.getAtom(j).getAtomTypeName() + "(" + molecule.getAtomNumber(molecule.getAtom(j)) + "), " + ((IAtom)atomConnected.get(k)).getAtomTypeName() + "(" + molecule.getAtomNumber((IAtom)atomConnected.get(k)) + ")");
158
stretchBendInteractionsData = pc.getBondAngleInteractionData(strbndType, atomConnected[i].getAtomTypeName(), molecule.getAtom(j).getAtomTypeName(), atomConnected[k].getAtomTypeName());
160
if (stretchBendInteractionsData == null) {
161
if (angleType == "1") {
162
if (strbndType == "1") {strbndType = "2";}
163
else {strbndType = "1";}
164
//logger.debug("strbnd: " + strbndType + ", " + ((IAtom)atomConnected.get(i)).getAtomTypeName() + "(" + molecule.getAtomNumber((IAtom)atomConnected.get(i)) + "), " + molecule.getAtom(j).getAtomTypeName() + "(" + molecule.getAtomNumber(molecule.getAtom(j)) + "), " + ((IAtom)atomConnected.get(k)).getAtomTypeName() + "(" + molecule.getAtomNumber((IAtom)atomConnected.get(k)) + ")");
165
stretchBendInteractionsData = pc.getBondAngleInteractionData(strbndType, atomConnected[i].getAtomTypeName(), molecule.getAtom(j).getAtomTypeName(), atomConnected[k].getAtomTypeName());
169
if (stretchBendInteractionsData == null) {
170
iR = ((IntegerResult)descriptor.calculate(atomConnected[i],molecule).getValue()).intValue();
171
jR = ((IntegerResult)descriptor.calculate(molecule.getAtom(j),molecule).getValue()).intValue();
172
kR = ((IntegerResult)descriptor.calculate(atomConnected[k],molecule).getValue()).intValue();
173
stretchBendInteractionsData = pc.getDefaultStretchBendData(iR, jR, kR);
176
//logger.debug("stretchBendInteractionsData : " + stretchBendInteractionsData);
177
kbaIJK[l] = ((Double) stretchBendInteractionsData.get(0)).doubleValue();
178
kbaKJI[l] = ((Double) stretchBendInteractionsData.get(1)).doubleValue();
180
//logger.debug("kbaIJK[" + l + "] = " + kbaIJK[l]);
181
//logger.debug("kbaKJI[" + l + "] = " + kbaKJI[l]);
184
bondData = pc.getBondData(bondIJType, atomConnected[i].getAtomTypeName(), molecule.getAtom(j).getAtomTypeName());
185
r0IJ[l] = ((Double) bondData.get(0)).doubleValue();
186
bondData = pc.getBondData(bondKJType, atomConnected[k].getAtomTypeName(), molecule.getAtom(j).getAtomTypeName());
187
r0KJ[l] = ((Double) bondData.get(0)).doubleValue();
189
bondijAtomPosition[l] = new int[2];
190
bondijAtomPosition[l][0] = molecule.getAtomNumber(atomConnected[i]);
191
bondijAtomPosition[l][1] = j;
193
bondkjAtomPosition[l] = new int[2];
194
bondkjAtomPosition[l][0] = molecule.getAtomNumber(atomConnected[k]);
195
bondkjAtomPosition[l][1] = j;
200
rij = new double[ab.angleNumber];
201
rkj = new double[ab.angleNumber];
202
deltarij = new double[ab.angleNumber];
203
deltarkj = new double[ab.angleNumber];
204
currentCoordinates = new GVector(3 * molecule.getAtomCount());
205
gradientCurrentCoordinates = new GVector(3 * molecule.getAtomCount());
206
gradientMMFF94SumEBA = new GVector(3 * molecule.getAtomCount());
207
dDeltarij = new double[3 * molecule.getAtomCount()][];
208
dDeltarkj = new double[3 * molecule.getAtomCount()][];
209
dDeltav = new double[3 * molecule.getAtomCount()][];
210
hessianMMFF94SumEBA = new GMatrix(3 * molecule.getAtomCount(), 3 * molecule.getAtomCount());
211
for (int i = 0; i < 3 * molecule.getAtomCount(); i++) {
212
dDeltarij[i] = new double[ab.angleNumber];
213
dDeltarkj[i] = new double[ab.angleNumber];
214
dDeltav[i] = new double[ab.angleNumber];
217
this.moleculeCurrentCoordinates = new GVector(3 * molecule.getAtomCount());
218
for (int i=0; i<moleculeCurrentCoordinates.getSize(); i++) {
219
this.moleculeCurrentCoordinates.setElement(i,1E10);
222
this.changeAtomCoordinates = new boolean[molecule.getAtomCount()];
228
* Calculate the current bond distances rij and rkj for each angle j, and the
229
* difference with the reference bonds.
231
*@param coords3d Current molecule coordinates.
233
public void setDeltarijAndDeltarkj(GVector coords3d) {
235
changedCoordinates = 0;
236
//logger.debug("Setting Deltarij and Deltarkj");
237
for (int i=0; i < changeAtomCoordinates.length; i++) {
238
this.changeAtomCoordinates[i] = false;
240
this.moleculeCurrentCoordinates.sub(coords3d);
242
for (int i = 0; i < this.moleculeCurrentCoordinates.getSize(); i++) {
243
//logger.debug("moleculeCurrentCoordinates " + i + " = " + this.moleculeCurrentCoordinates.getElement(i));
244
if (Math.abs(this.moleculeCurrentCoordinates.getElement(i)) > 0) {
245
changeAtomCoordinates[i/3] = true;
246
changedCoordinates = changedCoordinates + 1;
247
//logger.debug("changeAtomCoordinates[" + i/3 + "] = " + changeAtomCoordinates[i/3]);
252
for (int i = 0; i < ab.angleNumber; i++) {
253
if ((changeAtomCoordinates[ab.angleAtomPosition[i][0]] == true) |
254
(changeAtomCoordinates[ab.angleAtomPosition[i][1]] == true)) {
256
rij[i] = ForceFieldTools.distanceBetweenTwoAtomsFrom3xNCoordinates(coords3d, ab.angleAtomPosition[i][1], ab.angleAtomPosition[i][0]);
257
deltarij[i] = rij[i] - r0IJ[i];
258
//logger.debug("deltarij[" + i + "] = " + deltarij[i]);
260
//else {System.out.println("deltarij[" + i + "] was no recalculated");}
261
if ((changeAtomCoordinates[ab.angleAtomPosition[i][1]] == true) |
262
(changeAtomCoordinates[ab.angleAtomPosition[i][2]] == true)) {
264
rkj[i] = ForceFieldTools.distanceBetweenTwoAtomsFrom3xNCoordinates(coords3d, ab.angleAtomPosition[i][1], ab.angleAtomPosition[i][2]);
265
deltarkj[i] = rkj[i] - r0KJ[i];
266
//logger.debug("deltarkj[" + i + "] = " + deltarkj[i]);
268
//else {System.out.println("deltarkj[" + i + "] was no recalculated");}
270
/*if (changedCoordinates == changeAtomCoordinates.length) {
271
for (int m = 0; m < ab.angleNumber; m++) {
272
System.out.println("phi[" + m + "] = " + Math.toDegrees(phi[m]));
276
moleculeCurrentCoordinates.set(coords3d);
282
* Set the MMFF94 stretch-bend interaction term given the atoms cartesian
285
*@param coords3d Current molecule coordinates.
287
public void setFunctionMMFF94SumEBA(GVector coords3d) {
288
//ab.setAngleBendingFlag(false);
289
if (currentCoordinates.equals(coords3d)) {
291
setDeltarijAndDeltarkj(coords3d);
292
ab.setDeltav(coords3d);
294
for (int j = 0; j < ab.angleNumber; j++) {
295
//logger.debug("kbaIJK[" + j + "] = " + kbaIJK[j]);
296
//logger.debug("kbaKJI[" + j + "] = " + kbaKJI[j]);
297
//logger.debug("deltarij[" + j + "] = " + deltarij[j]);
298
//logger.debug("deltarkj[" + j + "] = " + deltarkj[j]);
299
//logger.debug("ab.deltav[" + j + "] = " + ab.deltav[j]);
300
mmff94SumEBA = mmff94SumEBA + 2.51210 * (kbaIJK[j] * deltarij[j] + kbaKJI[j] * deltarkj[j]) * ab.deltav[j];
301
//logger.debug("mmff94SumEBA = " + mmff94SumEBA);
303
//mmff94SumEBA = Math.abs(mmff94SumEBA);
304
//logger.debug("mmff94SumEBA = " + mmff94SumEBA);
305
currentCoordinates.set(coords3d);
311
* Get the MMFF94 stretch-bend interaction term.
313
*@return MMFF94 stretch-bend interaction term value.
315
public double getFunctionMMFF94SumEBA() {
321
* Evaluate the gradient of the stretch-bend interaction term.
323
*@param coords3d Current molecule coordinates.
325
public void setGradientMMFF94SumEBA(GVector coords3d) {
327
if (currentCoordinates.equals(coords3d)) {
329
setFunctionMMFF94SumEBA(coords3d);
332
bs.setBondLengthsFirstDerivative(coords3d, deltarij, bondijAtomPosition);
333
dDeltarij = bs.getBondLengthsFirstDerivative();
334
bs.setBondLengthsFirstDerivative(coords3d, deltarkj, bondkjAtomPosition);
335
dDeltarkj = bs.getBondLengthsFirstDerivative();
336
ab.setAngleBending2ndOrderErrorApproximateGradient(coords3d);
337
dDeltav = ab.getAngleBending2ndOrderErrorApproximateGradient();
339
if (dDeltav == null) {logger.debug("setGradient: dDeltav null");}
340
double sumGradientEBA;
341
for (int i = 0; i < gradientMMFF94SumEBA.getSize(); i++) {
343
for (int j = 0; j < ab.angleNumber; j++) {
344
sumGradientEBA = sumGradientEBA + (kbaIJK[j] * dDeltarij[i][j] + kbaKJI[j] * dDeltarkj[i][j]) * ab.deltav[j]
345
+ (kbaIJK[j] * deltarij[j] + kbaKJI[j] * deltarkj[j]) * ab.angleBendingOrder2ndErrorApproximateGradient[i][j];
347
sumGradientEBA = sumGradientEBA * 2.51210;
349
gradientMMFF94SumEBA.setElement(i, sumGradientEBA);
350
gradientCurrentCoordinates.set(coords3d);
352
//logger.debug("gradientMMFF94SumEBA = " + gradientMMFF94SumEBA);
357
* Get the gradient of the stretch-bend interaction term.
359
*@return stretch-bend interaction gradient value.
361
public GVector getGradientMMFF94SumEBA() {
362
return gradientMMFF94SumEBA;
367
* Evaluate a 2nd order approximation of the gradient for the stretch-bend interaction term,
368
* given the atoms coordinates.
370
*@param coord3d Current molecule coordinates.
372
public void set2ndOrderErrorApproximateGradientMMFF94SumEBA(GVector coord3d) {
373
order2ndErrorApproximateGradientMMFF94SumEBA = new GVector(coord3d.getSize());
374
double sigma = Math.pow(0.000000000000001,0.33);
375
GVector xplusSigma = new GVector(coord3d.getSize());
376
GVector xminusSigma = new GVector(coord3d.getSize());
377
double fInXplusSigma = 0;
378
double fInXminusSigma = 0;
380
for (int m = 0; m < order2ndErrorApproximateGradientMMFF94SumEBA.getSize(); m++) {
381
xplusSigma.set(coord3d);
382
xplusSigma.setElement(m,coord3d.getElement(m) + sigma);
383
this.setFunctionMMFF94SumEBA(xplusSigma);
384
fInXplusSigma = this.getFunctionMMFF94SumEBA();
385
xminusSigma.set(coord3d);
386
xminusSigma.setElement(m,coord3d.getElement(m) - sigma);
387
this.setFunctionMMFF94SumEBA(xminusSigma);
388
fInXminusSigma = this.getFunctionMMFF94SumEBA();
389
order2ndErrorApproximateGradientMMFF94SumEBA.setElement(m,(fInXplusSigma - fInXminusSigma) / (2 * sigma));
392
//logger.debug("order2ndErrorApproximateGradientMMFF94SumEBA : " + order2ndErrorApproximateGradientMMFF94SumEBA);
397
* Get the 2nd order error approximate gradient for the stretch-bend term.
400
*@return Stretch-bend interaction 2nd order error approximate gradient value.
402
public GVector get2ndOrderErrorApproximateGradientMMFF94SumEBA() {
403
return order2ndErrorApproximateGradientMMFF94SumEBA;
408
* Evaluate a 5th order error approximation of the gradient, of the stretch-bend interaction term, for a given atoms
411
*@param coord3d Current molecule coordinates.
413
public void set5thOrderErrorApproximateGradientMMFF94SumEBA(GVector coord3d) {
414
order5thErrorApproximateGradientMMFF94SumEBA = new GVector(coord3d.getSize());
415
double sigma = Math.pow(0.000000000000001,0.2);
416
GVector xplusSigma = new GVector(coord3d.getSize());
417
GVector xminusSigma = new GVector(coord3d.getSize());
418
GVector xplus2Sigma = new GVector(coord3d.getSize());
419
GVector xminus2Sigma = new GVector(coord3d.getSize());
420
double fInXplusSigma = 0;
421
double fInXminusSigma = 0;
422
double fInXplus2Sigma = 0;
423
double fInXminus2Sigma = 0;
425
for (int m=0; m < order5thErrorApproximateGradientMMFF94SumEBA.getSize(); m++) {
426
xplusSigma.set(coord3d);
427
xplusSigma.setElement(m,coord3d.getElement(m) + sigma);
428
this.setFunctionMMFF94SumEBA(xplusSigma);
429
fInXplusSigma = this.getFunctionMMFF94SumEBA();
430
xminusSigma.set(coord3d);
431
xminusSigma.setElement(m,coord3d.getElement(m) - sigma);
432
this.setFunctionMMFF94SumEBA(xminusSigma);
433
fInXminusSigma = this.getFunctionMMFF94SumEBA();
434
xplus2Sigma.set(coord3d);
435
xplus2Sigma.setElement(m,coord3d.getElement(m) + 2 * sigma);
436
this.setFunctionMMFF94SumEBA(xplus2Sigma);
437
fInXplus2Sigma = this.getFunctionMMFF94SumEBA();
438
xminus2Sigma.set(coord3d);
439
xminus2Sigma.setElement(m,coord3d.getElement(m) - 2 * sigma);
440
this.setFunctionMMFF94SumEBA(xminus2Sigma);
441
fInXminus2Sigma = this.getFunctionMMFF94SumEBA();
442
order5thErrorApproximateGradientMMFF94SumEBA.setElement(m, (8 * (fInXplusSigma - fInXminusSigma) - (fInXplus2Sigma - fInXminus2Sigma)) / (12 * sigma));
445
//logger.debug("order5thErrorApproximateGradientMMFF94SumEBA : " + order5thErrorApproximateGradientMMFF94SumEBA);
450
* Get the 5 order approximate gradient of the stretch-bend interaction term.
452
*@return stretch-bend interaction 5 order approximate gradient value.
454
public GVector get5thOrderErrorApproximateGradientMMFF94SumEBA() {
455
return order5thErrorApproximateGradientMMFF94SumEBA;
460
* Evaluate the hessian of the stretch-bend interaction.
462
*@param coords3d Current molecule coordinates.
464
public void setHessianMMFF94SumEBA(GVector coords3d) {
466
double[] forHessian = new double[coords3d.getSize() * coords3d.getSize()];
468
if (currentCoordinates.equals(coords3d)) {
470
setFunctionMMFF94SumEBA(coords3d);
473
if (dDeltarij == null) {logger.debug("dDeltarij null");}
474
if (gradientCurrentCoordinates.equals(coords3d) == false) {
475
bs.setBondLengthsFirstDerivative(coords3d, deltarij, bondijAtomPosition);
476
dDeltarij = bs.getBondLengthsFirstDerivative();
478
if (dDeltarkj == null) {logger.debug("dDeltarkj null");}
479
if (gradientCurrentCoordinates.equals(coords3d) == false) {
480
bs.setBondLengthsFirstDerivative(coords3d, deltarkj, bondkjAtomPosition);
481
dDeltarkj = bs.getBondLengthsFirstDerivative();
483
if (dDeltav == null) {logger.debug("setHessian: dDeltav null");}
484
if (gradientCurrentCoordinates.equals(coords3d) == false) {
485
//logger.debug("ab.setAngleBending2ndOrderErrorApproximateGradient()");
486
ab.setAngleBending2ndOrderErrorApproximateGradient(coords3d);
487
dDeltav = ab.getAngleBending2ndOrderErrorApproximateGradient();
490
ab.setAngleBending2ndOrderErrorApproximateHessian(coords3d);
491
double[][][] ddDeltav = ab.getAngleBending2ndOrderErrorApproximateHessian();
492
bs.setBondLengthsSecondDerivative(coords3d, deltarij, bondijAtomPosition);
493
double[][][] ddDeltarij = bs.getBondLengthsSecondDerivative();
494
bs.setBondLengthsSecondDerivative(coords3d, deltarkj, bondkjAtomPosition);
495
double[][][] ddDeltarkj = bs.getBondLengthsSecondDerivative();
497
if (dDeltav == null) {logger.debug("setHessian: dDeltav null");}
498
//logger.debug("ab.angleNumber = " + ab.angleNumber);
499
double sumHessianEBA;
501
for (int i = 0; i < coords3d.getSize(); i++) {
502
for (int j = 0; j < coords3d.getSize(); j++) {
503
forHessianIndex = i*coords3d.getSize()+j;
505
for (int k = 0; k < ab.angleNumber; k++) {
506
sumHessianEBA = sumHessianEBA + (kbaIJK[k] * ddDeltarij[i][j][k] + kbaKJI[k] * ddDeltarkj[i][j][k]) * ab.deltav[k]
507
+ (kbaIJK[k] * dDeltarij[j][k] + kbaKJI[k] * dDeltarkj[j][k]) * dDeltav[j][k]
508
+ (kbaIJK[k] * dDeltarij[j][k] + kbaKJI[k] * dDeltarkj[j][k]) * dDeltav[j][k]
509
+ (kbaIJK[k] * deltarij[k] + kbaKJI[k] * deltarkj[k]) * ddDeltav[i][j][k];
511
forHessian[forHessianIndex] = sumHessianEBA;
515
hessianMMFF94SumEBA.setSize(coords3d.getSize(), coords3d.getSize());
516
hessianMMFF94SumEBA.set(forHessian);
517
//logger.debug("hessianMMFF94SumEBA : " + hessianMMFF94SumEBA);
522
* Get the hessian of the stretch-bend interaction.
524
*@return Hessian value of the stretch-bend interaction term.
526
public GMatrix getHessianMMFF94SumEBA() {
527
return hessianMMFF94SumEBA;