1
package org.openscience.cdk.modeling.forcefield;
3
import java.util.Hashtable;
5
import javax.vecmath.GMatrix;
6
import javax.vecmath.GVector;
8
import org.openscience.cdk.interfaces.IAtomContainer;
9
import org.openscience.cdk.qsar.IAtomicDescriptor;
10
import org.openscience.cdk.qsar.descriptors.atomic.BondsToAtomDescriptor;
11
import org.openscience.cdk.qsar.result.IntegerResult;
12
//import org.openscience.cdk.tools.LoggingTool;
16
* MMFF94 Electrostatic Interactions energy. Include function and derivatives.
19
*@cdk.created May 13, 2005
20
*@cdk.module forcefield
22
public class ElectrostaticInteractions {
24
String functionShape = " Electrostatic Interactions ";
26
double mmff94SumEQ = 0;
27
GVector gradientMMFF94SumEQ = null;
28
GVector order2ndErrorApproximateGradientMMFF94SumEQ = null;
29
GVector order5thErrorApproximateGradientMMFF94SumEQ = null;
30
GMatrix hessianMMFF94SumEQ = null;
31
double[] forHessian = null;
33
double[][] dR = null; // internuclear separation first order derivative respect to atoms coordinates
34
double[][][] ddR = null; // internuclear separation second order derivative respect to atoms coordinates
36
IAtomicDescriptor shortestPathBetweenTwoAtoms = new BondsToAtomDescriptor();
37
Object[] params = {new Integer(0)};
39
int electrostaticInteractionNumber;
40
int[][] electrostaticInteractionAtomPosition = null;
42
double[] r = null; // internuclear separation in Angstroms.
46
double delta = 0.05; //electrostatic buffering constant.
51
double electrostatic14interactionsScale = 0.75; // Scale factor for 1-4 interactions. To take in the future from mmff94.prm files.
53
//private LoggingTool logger;
56
* Constructor for the ElectrostaticInteractions object
58
public ElectrostaticInteractions() {
59
//logger = new LoggingTool(this);
64
* Set CCG Electrostatic parameters for the molecule.
67
*@param molecule The molecule like an AtomContainer object.
68
*@param parameterSet MMFF94 parameters set
69
*@exception Exception Description of the Exception
71
public void setMMFF94ElectrostaticParameters(IAtomContainer molecule, Hashtable parameterSet) throws Exception {
73
//distances = wnd.getShortestPathLengthBetweenAtoms((AtomContainer) molecule);
75
//logger.debug("molecule.getAtomCount() : " + molecule.getAtomCount());
76
//logger.debug("molecule.getBondCount() : " + molecule.getBondCount());
77
if (molecule.getAtomCount() == 12 & molecule.getBondCount() == 11) {
78
molecule.getAtom(3).setCharge(1);
79
molecule.getAtom(8).setCharge(1);
82
electrostaticInteractionNumber = 0;
83
for (int i=0; i<molecule.getAtomCount(); i++) {
84
for (int j=i+1; j<molecule.getAtomCount(); j++) {
85
params[0] = new Integer(j);
86
shortestPathBetweenTwoAtoms.setParameters(params);
87
//if (distances[molecule.getAtomNumber(molecule.getAtomAt(i))][molecule.getAtomNumber(molecule.getAtomAt(j))]>2) {
88
if (((IntegerResult)shortestPathBetweenTwoAtoms.calculate(molecule.getAtom(i),molecule).getValue()).intValue()>2){
89
electrostaticInteractionNumber += 1;
93
//logger.debug("electrostaticInteractionNumber : " + electrostaticInteractionNumber);
95
qi = new double[electrostaticInteractionNumber];
96
qj = new double[electrostaticInteractionNumber];
97
r = new double[electrostaticInteractionNumber];
98
iQ = new double[electrostaticInteractionNumber];
100
electrostaticInteractionAtomPosition = new int[electrostaticInteractionNumber][];
103
for (int i=0; i<molecule.getAtomCount(); i++) {
104
for (int j=i+1; j<molecule.getAtomCount(); j++) {
105
params[0] = new Integer(j);
106
shortestPathBetweenTwoAtoms.setParameters(params);
107
//if (distances[molecule.getAtomNumber(molecule.getAtomAt(i))][molecule.getAtomNumber(molecule.getAtomAt(j))]>2) {
108
if (((IntegerResult)shortestPathBetweenTwoAtoms.calculate(molecule.getAtom(i),molecule).getValue()).intValue()>2){
110
qi[l]= molecule.getAtom(i).getCharge();
111
qj[l]= molecule.getAtom(j).getCharge();
112
//logger.debug("qi[" + l + "] = " + qi[l] + ", qj[" + l + "] = " + qj[l]);
113
if (((IntegerResult)shortestPathBetweenTwoAtoms.calculate(molecule.getAtom(i),molecule).getValue()).intValue()==3){
114
iQ[l] = electrostatic14interactionsScale;
119
electrostaticInteractionAtomPosition[l] = new int[2];
120
electrostaticInteractionAtomPosition[l][0] = i;
121
electrostaticInteractionAtomPosition[l][1] = j;
122
//logger.debug("electrostaticInteractionAtomPosition " + l + " : " + electrostaticInteractionAtomPosition[l][0] + ", " + electrostaticInteractionAtomPosition[l][1]);
130
* Calculate the internuclear separation Rij
132
*@param coords3d Current molecule coordinates.
134
public void setInternuclearSeparation(GVector coords3d) {
136
for (int l = 0; l < electrostaticInteractionNumber; l++) {
138
r[l] = ForceFieldTools.distanceBetweenTwoAtomsFrom3xNCoordinates(coords3d, electrostaticInteractionAtomPosition[l][0], electrostaticInteractionAtomPosition[l][1]);
139
//logger.debug("r[" + l + "]= " + r[l]);
145
* Get the internuclear separation values (Rij).
147
*@return Internuclear separation values.
149
public double[] getInternuclearSeparation() {
155
* Evaluate the MMFF94 Electrostatic interaction energy.
157
*@param coords3d Current molecule coordinates.
158
*@return MMFF94 Electrostatic interaction term value.
160
public double functionMMFF94SumEQ(GVector coords3d) {
161
setInternuclearSeparation(coords3d);
163
for (int l = 0; l < electrostaticInteractionNumber; l++) {
164
mmff94SumEQ = mmff94SumEQ + iQ[l] * 332.0716 * qi[l] * qj[l] / (D * Math.pow(r[l] + delta, n));
165
//logger.debug("mmff94SumEQ = " + mmff94SumEQ);
167
//logger.debug("mmff94SumEQ = " + mmff94SumEQ);
173
* Calculate the internuclear separation (Rij) first derivative respect to the cartesian coordinates of the atoms.
175
*@param coord3d Current molecule coordinates.
177
public void setInternuclearSeparationFirstOrderDerivative(GVector coord3d) {
179
dR = new double[coord3d.getSize()][];
180
setInternuclearSeparation(coord3d);
182
Double forAtomNumber = null;
185
for (int i = 0; i < dR.length; i++) {
187
dR[i] = new double[electrostaticInteractionNumber];
189
forAtomNumber = new Double(i/3);
191
//logger.debug("coordinate = " + coordinate);
193
atomNumber = forAtomNumber.intValue();
194
//logger.debug("atomNumber = " + atomNumber);
196
for (int j = 0; j < electrostaticInteractionNumber; j++) {
198
if ((electrostaticInteractionAtomPosition[j][0] == atomNumber) | (electrostaticInteractionAtomPosition[j][1] == atomNumber)) {
199
//logger.debug("atomNumber, r[" + j + "] = " + r[j]);
200
switch (coordinate) {
202
case 0: dR[i][j] = (coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][0]) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][1])) / r[j];
203
//logger.debug("xi-xj = " + (coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][0]) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][1])));
206
case 1: dR[i][j] = (coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][0] + 1) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][1] + 1)) / r[j];
207
//logger.debug("xi-xj = " + (coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][0]) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][1])));
210
case 2: dR[i][j] = (coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][0] + 2) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][1] + 2)) / r[j];
211
//logger.debug("xi-xj = " + (coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][0]) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[j][1])));
214
if (electrostaticInteractionAtomPosition[j][1] == atomNumber) {
215
dR[i][j] = (-1) * dR[i][j];
220
//logger.debug("electrostaticInteraction " + j + " : " + "dR[" + i + "][" + j + "] = " + dR[i][j]);
227
* Get the internuclear separation first order derivative respect to the cartesian coordinates of the atoms.
229
*@return Internuclear separation first order derivative value [dimension(3xN)] [vdW interaction number]
231
public double[][] getInternuclearSeparationFirstDerivative() {
237
* Set the gradient of the MMFF94 Electrostatic interaction term.
240
*@param coords3d Current molecule coordinates.
242
public void setGradientMMFF94SumEQ(GVector coords3d) {
244
gradientMMFF94SumEQ = new GVector(coords3d.getSize());
245
setInternuclearSeparation(coords3d);
246
setInternuclearSeparationFirstOrderDerivative(coords3d);
248
double sumGradientEQ;
249
for (int i = 0; i < gradientMMFF94SumEQ.getSize(); i++) {
251
for (int l = 0; l < electrostaticInteractionNumber; l++) {
252
sumGradientEQ = sumGradientEQ + ((-332.0716 * qi[l] * qj[l] * n)/(D * Math.pow(r[l] + delta, n+1))) * dR[i][l];
254
gradientMMFF94SumEQ.setElement(i, sumGradientEQ);
256
//logger.debug("gradientMMFF94SumEQ = " + gradientMMFF94SumEQ);
261
* Get the gradient of the MMFF94 Electrostatic interaction term.
264
*@return MMFF94 Electrostatic interaction gradient value.
266
public GVector getGradientMMFF94SumEQ() {
267
return gradientMMFF94SumEQ;
272
* Evaluate a 2nd order error approximation of the gradient, for the Electrostatic interaction term, given the atoms
275
*@param coord3d Current molecule coordinates.
277
/* public void set2ndOrderErrorApproximateGradientMMFF94SumEQ(GVector coord3d) {
278
order2ndErrorApproximateGradientMMFF94SumEQ = new GVector(coord3d.getSize());
279
double sigma = Math.pow(0.000000000000001,0.33);
280
GVector xplusSigma = new GVector(coord3d.getSize());
281
GVector xminusSigma = new GVector(coord3d.getSize());
283
for (int m = 0; m < order2ndErrorApproximateGradientMMFF94SumEQ.getSize(); m++) {
284
xplusSigma.set(coord3d);
285
xplusSigma.setElement(m,coord3d.getElement(m) + sigma);
286
xminusSigma.set(coord3d);
287
xminusSigma.setElement(m,coord3d.getElement(m) - sigma);
288
order2ndErrorApproximateGradientMMFF94SumEQ.setElement(m,(functionMMFF94SumEQ(xplusSigma) - functionMMFF94SumEQ(xminusSigma)) / (2 * sigma));
291
//logger.debug("order2ndErrorApproximateGradientMMFF94SumEQ : " + order2ndErrorApproximateGradientMMFF94SumEQ);
296
* Get the 2nd order error approximate gradient for the Electrostatic interaction term.
299
*@return Electrostatic interaction 2nd order error approximate gradient value
301
/* public GVector get2ndOrderErrorApproximateGradientMMFF94SumEQ() {
302
return order2ndErrorApproximateGradientMMFF94SumEQ;
307
* Evaluate a 5th order error approximation of the gradient, for the Electrostatic interaction term, given the atoms
310
*@param coords3d Current molecule coordinates.
312
/* public void set5thOrderErrorApproximateGradientMMFF94SumEQ(GVector coord3d) {
313
order5thErrorApproximateGradientMMFF94SumEQ = new GVector(coord3d.getSize());
314
double sigma = Math.pow(0.000000000000001,0.2);
315
GVector xplusSigma = new GVector(coord3d.getSize());
316
GVector xminusSigma = new GVector(coord3d.getSize());
317
GVector xplus2Sigma = new GVector(coord3d.getSize());
318
GVector xminus2Sigma = new GVector(coord3d.getSize());
320
for (int m=0; m < order5thErrorApproximateGradientMMFF94SumEQ.getSize(); m++) {
321
xplusSigma.set(coord3d);
322
xplusSigma.setElement(m,coord3d.getElement(m) + sigma);
323
xminusSigma.set(coord3d);
324
xminusSigma.setElement(m,coord3d.getElement(m) - sigma);
325
xplus2Sigma.set(coord3d);
326
xplus2Sigma.setElement(m,coord3d.getElement(m) + 2 * sigma);
327
xminus2Sigma.set(coord3d);
328
xminus2Sigma.setElement(m,coord3d.getElement(m) - 2 * sigma);
329
order5thErrorApproximateGradientMMFF94SumEQ.setElement(m, (8 * (functionMMFF94SumEQ(xplusSigma) - functionMMFF94SumEQ(xminusSigma)) - (functionMMFF94SumEQ(xplus2Sigma) - functionMMFF94SumEQ(xminus2Sigma))) / (12 * sigma));
332
//logger.debug("order5thErrorApproximateGradientMMFF94SumEQ : " + order5thErrorApproximateGradientMMFF94SumEQ);
337
* Get the 5th order error approximate gradient for the Electrostatic interaction term.
339
*@return Electrostatic interaction 5th order error approximate gradient value.
341
/* public GVector get5OrderApproximateGradientMMFF94SumEQ() {
342
return order5thErrorApproximateGradientMMFF94SumEQ;
348
* Calculate the internuclear separation second derivative respect to the cartesian coordinates of the atoms.
350
*@param coord3d Current molecule coordinates.
352
public void setInternuclearSeparationSecondDerivative(GVector coord3d) {
353
ddR = new double[coord3d.getSize()][][];
355
Double forAtomNumber = null;
360
double ddR1=0; // ddR[i][j][k] = ddR1 - ddR2
363
setInternuclearSeparationFirstOrderDerivative(coord3d);
365
for (int i=0; i<coord3d.getSize(); i++) {
366
ddR[i] = new double[coord3d.getSize()][];
368
forAtomNumber = new Double(i/3);
370
atomNumberi = forAtomNumber.intValue();
371
//logger.debug("atomNumberi = " + atomNumberi);
374
//logger.debug("coordinatei = " + coordinatei);
376
for (int j=0; j<coord3d.getSize(); j++) {
377
ddR[i][j] = new double[electrostaticInteractionNumber];
379
forAtomNumber = new Double(j/3);
381
atomNumberj = forAtomNumber.intValue();
382
//logger.debug("atomNumberj = " + atomNumberj);
385
//logger.debug("coordinatej = " + coordinatej);
387
//logger.debug("atomj : " + molecule.getAtomAt(atomNumberj));
389
for (int k=0; k < electrostaticInteractionNumber; k++) {
391
if ((electrostaticInteractionAtomPosition[k][0] == atomNumberj) | (electrostaticInteractionAtomPosition[k][1] == atomNumberj)) {
392
if ((electrostaticInteractionAtomPosition[k][0] == atomNumberi) | (electrostaticInteractionAtomPosition[k][1] == atomNumberi)) {
395
if (electrostaticInteractionAtomPosition[k][0] == atomNumberj) {
398
if (electrostaticInteractionAtomPosition[k][1] == atomNumberj) {
401
if (electrostaticInteractionAtomPosition[k][0] == atomNumberi) {
404
if (electrostaticInteractionAtomPosition[k][1] == atomNumberi) {
410
switch (coordinatej) {
411
case 0: ddR2 = (coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][0]) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][1]));
412
//logger.debug("OK: d1 x");
414
case 1: ddR2 = (coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][0] + 1) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][1] + 1));
415
//logger.debug("OK: d1 y");
417
case 2: ddR2 = (coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][0] + 2) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][1] + 2));
418
//logger.debug("OK: d1 z");
422
if (electrostaticInteractionAtomPosition[k][1] == atomNumberj) {
424
//logger.debug("OK: bond 1");
427
switch (coordinatei) {
428
case 0: ddR2 = ddR2 * (coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][0]) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][1]));
429
//logger.debug("OK: have d2 x");
431
case 1: ddR2 = ddR2 * (coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][0] + 1) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][1] + 1));
432
//logger.debug("OK: have d2 y");
434
case 2: ddR2 = ddR2 * (coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][0] + 2) - coord3d.getElement(3 * electrostaticInteractionAtomPosition[k][1] + 2));
435
//logger.debug("OK: have d2 z");
439
if (electrostaticInteractionAtomPosition[k][1] == atomNumberi) {
441
//logger.debug("OK: d2 bond 1");
444
ddR2 = ddR2 / Math.pow(r[k],2);
447
ddR[i][j][k] = ddR1 - ddR2;
450
//logger.debug("OK: 0");
454
//logger.debug("OK: 0");
456
//logger.debug("Electrostatic interactionn " + k + " : " + "ddR[" + i + "][" + j + "][" + k + "] = " + ddR[i][j][k]);
464
* Get the internuclear separation second derivative respect to the cartesian coordinates of the atoms.
466
*@return Bond lengths second derivative value [dimension(3xN)] [bonds Number]
468
public double[][][] getInternuclearSeparationSecondDerivative() {
474
* Evaluate the second order partial derivative (hessian) for the Electrostatic interaction energy given the atoms coordinates
476
*@param coord3d Current molecule coordinates.
478
public void setHessianMMFF94SumEQ(GVector coord3d) {
480
forHessian = new double[coord3d.getSize() * coord3d.getSize()];
482
setInternuclearSeparationSecondDerivative(coord3d);
486
for (int i = 0; i < coord3d.getSize(); i++) {
487
for (int j = 0; j < coord3d.getSize(); j++) {
489
for (int k = 0; k < electrostaticInteractionNumber; k++) {
490
sumHessianEQ = sumHessianEQ + (((332.0716 * qi[k] * qj[k] * n * (n+1) / D*Math.pow(r[k]+delta,n+2)) * dR[i][k]) * dR[j][k]
491
+ (-332.0716 * qi[k] * qj[k] * n / D * Math.pow(r[k]+delta,n+1)) * ddR[i][j][k]);
493
forHessianIndex = i*coord3d.getSize()+j;
494
forHessian[forHessianIndex] = sumHessianEQ;
495
//logger.debug("forHessian[forHessianIndex] : " + forHessian[forHessianIndex]);
499
hessianMMFF94SumEQ = new GMatrix(coord3d.getSize(), coord3d.getSize(), forHessian);
500
//logger.debug("hessianMMFF94SumEQ : " + hessianMMFF94SumEQ);
505
* Get the hessian for the Electrostatic interaction energy.
507
*@return Hessian value of the Electrostatic interaction term.
509
public GMatrix getHessianMMFF94SumEQ() {
510
return hessianMMFF94SumEQ;
515
* Get the hessian for the Electrostatic interaction energy.
517
*@return Hessian value of the Electrostatic interaction term.
519
public double[] getForHessianMMFF94SumEQ() {