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
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.potential.nonbonded.implicit;
39
40 import static java.lang.String.format;
41 import static org.apache.commons.math3.util.FastMath.PI;
42 import static org.apache.commons.math3.util.FastMath.exp;
43 import static org.apache.commons.math3.util.FastMath.sqrt;
44 import static org.apache.commons.math3.util.FastMath.tanh;
45
46 import edu.rit.pj.IntegerForLoop;
47 import edu.rit.pj.ParallelRegion;
48 import edu.rit.pj.reduction.SharedDouble;
49 import ffx.potential.bonded.Angle;
50 import ffx.potential.bonded.Atom;
51 import ffx.potential.bonded.Bond;
52 import ffx.potential.bonded.Torsion;
53 import java.util.List;
54 import java.util.logging.Level;
55 import java.util.logging.Logger;
56
57
58
59
60
61
62 public class HydrophobicPMFRegion extends ParallelRegion {
63
64 private static final Logger logger = Logger.getLogger(HydrophobicPMFRegion.class.getName());
65
66 private final double rCarbon = 1.7;
67
68 private final double rWater = 1.4;
69
70 private final double safact = 0.3516;
71
72 private final double acSurf = 120.7628;
73
74 private final double tSlope = 100.0;
75
76 private final double tOffset = 6.0;
77
78 private final double hpmfCut = 11.0;
79
80 private final double hpmfCut2 = hpmfCut * hpmfCut;
81
82 private final double h1 = -0.7308004860404441194;
83 private final double h2 = 0.2001645051578760659;
84 private final double h3 = -0.0905499953418473502;
85
86 private final double c1 = 3.8167879266271396155;
87 private final double c2 = 5.4669162286016419472;
88 private final double c3 = 7.1167694861385353278;
89
90 private final double w1 = 1.6858993102248638341;
91 private final double w2 = 1.3906405621629980285;
92 private final double w3 = 1.5741657341338335385;
93 private final double rSurf = rCarbon + 2.0 * rWater;
94 private final double piSurf = PI * (rCarbon + rWater);
95
96 private final double[] rPMF;
97
98 private final int nCarbon;
99
100 private final int[] iCarbon;
101
102 private final double[] carbonSASA;
103
104 private final double[] tanhSA;
105
106 private final CarbonSASALoop[] carbonSASALoop;
107
108 private final HydrophobicPMFLoop[] hydrophobicPMFLoop;
109
110 private final CarbonSASACRLoop[] carbonSASACRLoop;
111
112 private final SharedDouble sharedEnergy;
113 private final double[] dtanhSA;
114 private final double[] sasa;
115 private final double[] carbonSASACR;
116 private Atom[] atoms;
117 private int nAtoms;
118 private double[] x, y, z;
119 private boolean[] use;
120 private double[][][] grad;
121 private boolean gradient;
122
123 public HydrophobicPMFRegion(
124 Atom[] atoms, double[] x, double[] y, double[] z, boolean[] use, double[][][] grad, int nt) {
125 logger.info(format(" Hydrophobic PMF cut-off: %8.2f (A)", hpmfCut));
126
127 this.atoms = atoms;
128 nAtoms = atoms.length;
129 this.x = x;
130 this.y = y;
131 this.z = z;
132 this.use = use;
133 this.grad = grad;
134
135
136 int count = 0;
137 for (int i = 0; i < nAtoms; i++) {
138 Atom atom = atoms[i];
139 int atomicNumber = atom.getAtomicNumber();
140 if (atomicNumber == 6) {
141 List<Bond> bonds = atom.getBonds();
142 int bondCount = bonds.size();
143 if (bondCount <= 2) {
144 continue;
145 }
146 boolean keep = true;
147 for (int j = 0; j < bondCount; j++) {
148 Atom atom2 = bonds.get(j).get1_2(atom);
149 int atomicNumber2 = atom2.getAtomicNumber();
150 if (bondCount == 3 && atomicNumber2 == 8) {
151 keep = false;
152 break;
153 }
154 }
155 if (keep) {
156 count++;
157 }
158 }
159 }
160
161 rPMF = new double[nAtoms];
162 nCarbon = count;
163 iCarbon = new int[nCarbon];
164 carbonSASA = new double[nCarbon];
165 carbonSASACR = new double[nCarbon];
166 tanhSA = new double[nCarbon];
167 dtanhSA = new double[nCarbon];
168 sasa = new double[nCarbon];
169
170 carbonSASALoop = new CarbonSASALoop[nt];
171 hydrophobicPMFLoop = new HydrophobicPMFLoop[nt];
172 carbonSASACRLoop = new CarbonSASACRLoop[nt];
173 for (int i = 0; i < nt; i++) {
174 carbonSASALoop[i] = new CarbonSASALoop();
175 hydrophobicPMFLoop[i] = new HydrophobicPMFLoop();
176 carbonSASACRLoop[i] = new CarbonSASACRLoop();
177 }
178 sharedEnergy = new SharedDouble();
179
180
181 int index = 0;
182 for (int i = 0; i < nAtoms; i++) {
183 Atom atom = atoms[i];
184 int atomicNumber = atom.getAtomicNumber();
185 if (atomicNumber == 6) {
186 int nh = 0;
187 List<Bond> bonds = atom.getBonds();
188 int bondCount = bonds.size();
189 if (bondCount <= 2) {
190 continue;
191 }
192 boolean keep = true;
193 for (int j = 0; j < bondCount; j++) {
194 Atom atom2 = bonds.get(j).get1_2(atom);
195 int atomicNumber2 = atom2.getAtomicNumber();
196 if (atomicNumber2 == 1) {
197 nh++;
198 }
199 if (bondCount == 3 && atomicNumber2 == 8) {
200 keep = false;
201 }
202 }
203 if (keep) {
204 iCarbon[index] = i;
205 carbonSASA[index] = 1.0;
206 if (bondCount == 3 && nh == 0) {
207 carbonSASA[index] = 1.554;
208 } else if (bondCount == 3 && nh == 1) {
209 carbonSASA[index] = 1.073;
210 } else if (bondCount == 4 && nh == 1) {
211 carbonSASA[index] = 1.276;
212 } else if (bondCount == 4 && nh == 2) {
213 carbonSASA[index] = 1.045;
214 } else if (bondCount == 4 && nh == 3) {
215 carbonSASA[index] = 0.880;
216 }
217 carbonSASA[index] = carbonSASA[index] * safact / acSurf;
218 if (logger.isLoggable(Level.FINEST)) {
219 logger.finest(
220 format(
221 " %d Base HPMF SASA for atom %d: %10.8f", index + 1, i + 1, carbonSASA[index]));
222 }
223 index++;
224 }
225 }
226 }
227
228
229 for (int i = 0; i < nAtoms; i++) {
230 rPMF[i] = 2.0;
231 int atmnum = atoms[i].getAtomicNumber();
232 switch (atmnum) {
233 case 0:
234 rPMF[i] = 0.0;
235 break;
236 case 1:
237 rPMF[i] = 1.20;
238 break;
239 case 2:
240 rPMF[i] = 1.40;
241 break;
242 case 5:
243 rPMF[i] = 1.80;
244 break;
245 case 6:
246 rPMF[i] = 1.70;
247 break;
248 case 7:
249 rPMF[i] = 1.55;
250 break;
251 case 8:
252 rPMF[i] = 1.50;
253 break;
254 case 9:
255 rPMF[i] = 1.47;
256 break;
257 case 10:
258 rPMF[i] = 1.54;
259 break;
260 case 14:
261 rPMF[i] = 2.10;
262 break;
263 case 15:
264 rPMF[i] = 1.80;
265 break;
266 case 16:
267 rPMF[i] = 1.80;
268 break;
269 case 17:
270 rPMF[i] = 1.75;
271 break;
272 case 18:
273 rPMF[i] = 1.88;
274 break;
275 case 34:
276 rPMF[i] = 1.90;
277 break;
278 case 35:
279 rPMF[i] = 1.85;
280 break;
281 case 36:
282 rPMF[i] = 2.02;
283 break;
284 case 53:
285 rPMF[i] = 1.98;
286 break;
287 case 54:
288 rPMF[i] = 2.16;
289 break;
290 }
291 }
292 }
293
294 public double getEnergy() {
295 return sharedEnergy.get();
296 }
297
298 @Override
299 public void run() {
300 int ti = getThreadIndex();
301 try {
302 execute(0, nCarbon - 1, carbonSASALoop[ti]);
303 execute(0, nCarbon - 2, hydrophobicPMFLoop[ti]);
304 if (gradient) {
305 execute(0, nCarbon - 1, carbonSASACRLoop[ti]);
306 }
307 } catch (Exception e) {
308 String message = "Fatal exception computing Born radii in thread " + ti + "\n";
309 logger.log(Level.SEVERE, message, e);
310 }
311 }
312
313 public void setGradient(boolean gradient) {
314 this.gradient = gradient;
315 }
316
317 @Override
318 public void start() {
319 sharedEnergy.set(0);
320 }
321
322
323
324
325
326
327 private class CarbonSASALoop extends IntegerForLoop {
328
329 @Override
330 public void run(int lb, int ub) {
331
332 for (int ii = lb; ii <= ub; ii++) {
333 final int i = iCarbon[ii];
334 if (!use[i]) {
335 continue;
336 }
337 final double carbonSA = carbonSASA[ii];
338 double sa = acSurf;
339 final double xi = x[i];
340 final double yi = y[i];
341 final double zi = z[i];
342 int count = 0;
343 for (int k = 0; k < nAtoms; k++) {
344 if (i != k && use[k]) {
345 final double xr = x[k] - xi;
346 final double yr = y[k] - yi;
347 final double zr = z[k] - zi;
348 final double r2 = xr * xr + yr * yr + zr * zr;
349 double rk = rPMF[k];
350 double rBig = rk + rSurf;
351 if (r2 < rBig * rBig) {
352 final double r = sqrt(r2);
353 final double rSmall = rk - rCarbon;
354 final double part = piSurf * (rBig - r) * (1.0 + rSmall / r);
355 sa *= (1.0 - carbonSA * part);
356 count++;
357 }
358 }
359 }
360 sasa[ii] = sa;
361
362 double tSA = tanh(tSlope * (sa - tOffset));
363 tanhSA[ii] = 0.5 * (1.0 + tSA);
364 dtanhSA[ii] = 0.5 * tSlope * (1.0 - tSA * tSA);
365 }
366 }
367 }
368
369
370
371
372
373
374 private class HydrophobicPMFLoop extends IntegerForLoop {
375
376
377 private final int[] omit;
378 private double energy;
379 private double[] gX;
380 private double[] gY;
381 private double[] gZ;
382
383 public HydrophobicPMFLoop() {
384 omit = new int[nAtoms];
385 }
386
387 @Override
388 public void finish() {
389 sharedEnergy.addAndGet(energy);
390 }
391
392 @Override
393 public void run(int lb, int ub) {
394
395 for (int ii = lb; ii <= ub; ii++) {
396 final int i = iCarbon[ii];
397 if (!use[i]) {
398 continue;
399 }
400 double tanhSAi = tanhSA[ii];
401 Atom ssAtom = null;
402 Atom atom = atoms[i];
403 List<Bond> bonds = atom.getBonds();
404 for (Bond bond : bonds) {
405 Atom atom2 = bond.get1_2(atom);
406 int k = atom2.getIndex() - 1;
407 if (!use[k]) {
408 continue;
409 }
410 omit[k] = i;
411 if (atom2.getAtomicNumber() == 16) {
412 ssAtom = atom2;
413 }
414 }
415 List<Angle> angles = atom.getAngles();
416 for (Angle angle : angles) {
417 Atom atom2 = angle.get1_3(atom);
418 if (atom2 != null) {
419 int k = atom2.getIndex() - 1;
420 if (!use[k]) {
421 continue;
422 }
423 omit[k] = i;
424 }
425 }
426 List<Torsion> torsions = atom.getTorsions();
427 for (Torsion torsion : torsions) {
428 Atom atom2 = torsion.get1_4(atom);
429 if (atom2 != null) {
430 int k = atom2.getIndex() - 1;
431 if (!use[k]) {
432 continue;
433 }
434 omit[k] = i;
435 if (ssAtom != null) {
436 List<Bond> bonds2 = atom2.getBonds();
437 for (Bond bond : bonds2) {
438 Atom s = bond.get1_2(atom2);
439 if (s.getAtomicNumber() == 16) {
440 List<Bond> sBonds = s.getBonds();
441 for (Bond sBond : sBonds) {
442 Atom s2 = sBond.get1_2(s);
443 if (s2 == ssAtom) {
444 omit[k] = -1;
445 }
446 }
447 }
448 }
449 }
450 }
451 }
452 final double xi = x[i];
453 final double yi = y[i];
454 final double zi = z[i];
455 double e = 0.0;
456 for (int kk = ii + 1; kk < nCarbon; kk++) {
457 int k = iCarbon[kk];
458 if (!use[k]) {
459 continue;
460 }
461 if (omit[k] != i) {
462 final double xr = xi - x[k];
463 final double yr = yi - y[k];
464 final double zr = zi - z[k];
465 final double r2 = xr * xr + yr * yr + zr * zr;
466 if (r2 < hpmfCut2) {
467 final double r = sqrt(r2);
468 final double a1 = (r - c1) * w1;
469 final double a2 = (r - c2) * w2;
470 final double a3 = (r - c3) * w3;
471 final double e1 = h1 * exp(-a1 * a1);
472 final double e2 = h2 * exp(-a2 * a2);
473 final double e3 = h3 * exp(-a3 * a3);
474 final double t1t2 = tanhSAi * tanhSA[kk];
475 final double sum = (e1 + e2 + e3);
476 e += sum * t1t2;
477 if (gradient) {
478
479 double de1 = -2.0 * e1 * a1 * w1;
480 double de2 = -2.0 * e2 * a2 * w2;
481 double de3 = -2.0 * e3 * a3 * w3;
482 double dsum = (de1 + de2 + de3) * t1t2 / r;
483 double dedx = dsum * xr;
484 double dedy = dsum * yr;
485 double dedz = dsum * zr;
486 gX[i] += dedx;
487 gY[i] += dedy;
488 gZ[i] += dedz;
489 gX[k] -= dedx;
490 gY[k] -= dedy;
491 gZ[k] -= dedz;
492
493 carbonSASACR[ii] += sum * tanhSA[kk] * dtanhSA[ii];
494 carbonSASACR[kk] += sum * tanhSA[ii] * dtanhSA[kk];
495 }
496 }
497 }
498 }
499 energy += e;
500 }
501 }
502
503 @Override
504 public void start() {
505 energy = 0.0;
506 for (int i = 0; i < nAtoms; i++) {
507 omit[i] = -1;
508 }
509 int threadID = getThreadIndex();
510 gX = grad[threadID][0];
511 gY = grad[threadID][1];
512 gZ = grad[threadID][2];
513 if (gradient) {
514 for (int i = 0; i < nCarbon; i++) {
515 carbonSASACR[i] = 0.0;
516 }
517 }
518 }
519 }
520
521
522
523
524
525
526 private class CarbonSASACRLoop extends IntegerForLoop {
527
528 private double[] gX;
529 private double[] gY;
530 private double[] gZ;
531
532 public CarbonSASACRLoop() {}
533
534 @Override
535 public void run(int lb, int ub) {
536 for (int ii = lb; ii <= ub; ii++) {
537 final int i = iCarbon[ii];
538 if (!use[i]) {
539 continue;
540 }
541 final double carbonSA = carbonSASA[ii];
542 final double xi = x[i];
543 final double yi = y[i];
544 final double zi = z[i];
545 for (int k = 0; k < nAtoms; k++) {
546 if (i != k && use[k]) {
547 final double xr = xi - x[k];
548 final double yr = yi - y[k];
549 final double zr = zi - z[k];
550 final double r2 = xr * xr + yr * yr + zr * zr;
551 double rk = rPMF[k];
552 double rBig = rk + rSurf;
553 if (r2 <= rBig * rBig) {
554 final double r = sqrt(r2);
555 final double rSmall = rk - rCarbon;
556 final double rr = 1.0 / r;
557 final double rr2 = rr * rr;
558 final double part = piSurf * (rBig - r) * (1.0 + rSmall * rr);
559 double t1b = -piSurf * (1.0 + rBig * rSmall * rr2);
560 double t1a = -sasa[ii] / (1.0 / carbonSA - part);
561 double de = t1a * t1b * rr * carbonSASACR[ii];
562 double dedx = de * xr;
563 double dedy = de * yr;
564 double dedz = de * zr;
565 gX[i] += dedx;
566 gY[i] += dedy;
567 gZ[i] += dedz;
568 gX[k] -= dedx;
569 gY[k] -= dedy;
570 gZ[k] -= dedz;
571 }
572 }
573 }
574 }
575 }
576
577 @Override
578 public void start() {
579 int threadID = getThreadIndex();
580 gX = grad[threadID][0];
581 gY = grad[threadID][1];
582 gZ = grad[threadID][2];
583 }
584 }
585 }