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 ffx.potential.nonbonded.VanDerWaalsForm.getCombinedEps;
41 import static ffx.potential.nonbonded.VanDerWaalsForm.getCombinedRadius;
42 import static org.apache.commons.math3.util.FastMath.PI;
43 import static org.apache.commons.math3.util.FastMath.max;
44 import static org.apache.commons.math3.util.FastMath.min;
45 import static org.apache.commons.math3.util.FastMath.pow;
46 import static org.apache.commons.math3.util.FastMath.sqrt;
47
48 import edu.rit.pj.IntegerForLoop;
49 import edu.rit.pj.ParallelRegion;
50 import edu.rit.pj.reduction.SharedDouble;
51 import ffx.crystal.Crystal;
52 import ffx.numerics.atomic.AtomicDoubleArray3D;
53 import ffx.potential.bonded.Atom;
54 import ffx.potential.parameters.VDWType.EPSILON_RULE;
55 import ffx.potential.parameters.VDWType.RADIUS_RULE;
56 import ffx.potential.parameters.ForceField;
57 import ffx.potential.parameters.VDWType;
58 import java.util.logging.Level;
59 import java.util.logging.Logger;
60
61
62
63
64
65
66
67 public class DispersionRegion extends ParallelRegion {
68
69
70 public static final double DEFAULT_DISPERSION_OFFSET = 1.056;
71
72 public static final double DEFAULT_SOLUTE_OFFSET = 0.0;
73
74 private static final Logger logger = Logger.getLogger(DispersionRegion.class.getName());
75
76 private static final double DEFAULT_DISP_OVERLAP_FACTOR = 0.75;
77
78
79
80
81 private static final double SLEVY = 1.0;
82
83 private static final double AWATER = 0.033428;
84
85 private static final double EPSO = 0.1100;
86
87 private static final double EPSH = 0.0135;
88
89 private static final double RMINO = 1.7025;
90
91 private static final double RMINH = 1.3275;
92
93 private static final EPSILON_RULE epsilonRule = VDWType.EPSILON_RULE.HHG;
94
95 private static final RADIUS_RULE radiusRule = VDWType.RADIUS_RULE.CUBIC_MEAN;
96
97 private final DispersionLoop[] dispersionLoop;
98 private final SharedDouble sharedDispersion;
99
100 protected Atom[] atoms;
101
102 private Crystal crystal;
103
104 private boolean[] use = null;
105
106 private int[][][] neighborLists;
107
108 private double[] x, y, z;
109
110 private double cut2;
111
112 private boolean gradient = false;
113
114 private AtomicDoubleArray3D grad;
115
116 private double dispersionOffest;
117
118
119
120
121 private double soluteOffset;
122
123 private double dispersionOverlapFactor;
124
125
126
127
128
129
130
131
132 public DispersionRegion(int nt, Atom[] atoms, ForceField forceField) {
133 dispersionLoop = new DispersionLoop[nt];
134 for (int i = 0; i < nt; i++) {
135 dispersionLoop[i] = new DispersionLoop();
136 }
137 sharedDispersion = new SharedDouble();
138
139 dispersionOffest = forceField.getDouble("DISPERSION_OFFSET", DEFAULT_DISPERSION_OFFSET);
140 soluteOffset = forceField.getDouble("SOLUTE_OFFSET", DEFAULT_SOLUTE_OFFSET);
141 dispersionOverlapFactor =
142 forceField.getDouble("DISP_OVERLAP_FACTOR", DEFAULT_DISP_OVERLAP_FACTOR);
143
144 allocate(atoms);
145 }
146
147
148
149
150
151
152
153
154
155 private static double tailCorrection(double r0, double eps, double rmin) {
156 if (r0 < rmin) {
157 double r03 = r0 * r0 * r0;
158 double rmin3 = rmin * rmin * rmin;
159 return -eps * 4.0 * PI * (rmin3 - r03) / 3.0 - eps * PI * 18.0 * rmin3 / 11.0;
160 } else {
161 double ri2 = r0 * r0;
162 double ri4 = ri2 * ri2;
163 double ri7 = r0 * ri2 * ri4;
164 double ri11 = ri7 * ri4;
165 double rmin2 = rmin * rmin;
166 double rmin4 = rmin2 * rmin2;
167 double rmin7 = rmin * rmin2 * rmin4;
168 return 2.0 * PI * eps * rmin7 * (2.0 * rmin7 - 11.0 * ri7) / (11.0 * ri11);
169 }
170 }
171
172
173
174
175
176
177 public void allocate(Atom[] atoms) {
178 this.atoms = atoms;
179 }
180
181
182
183
184
185
186 public void setDispersionOffest(double dispersionOffest) {
187 this.dispersionOffest = dispersionOffest;
188 }
189
190
191
192
193
194
195 public double getDispersionOffset() {
196 return dispersionOffest;
197 }
198
199 public double getDispersionOverlapFactor() {
200 return dispersionOverlapFactor;
201 }
202
203
204
205
206
207
208 public void setDispersionOverlapFactor(double dispersionOverlapFactor) {
209 this.dispersionOverlapFactor = dispersionOverlapFactor;
210 }
211
212 public double getEnergy() {
213 return sharedDispersion.get();
214 }
215
216 public double getSoluteOffset() {
217 return soluteOffset;
218 }
219
220 public void setSoluteOffset(double soluteOffset) {
221 this.soluteOffset = soluteOffset;
222 }
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 public void init(
239 Atom[] atoms,
240 Crystal crystal,
241 boolean[] use,
242 int[][][] neighborLists,
243 double[] x,
244 double[] y,
245 double[] z,
246 double cut2,
247 boolean gradient,
248 AtomicDoubleArray3D grad) {
249 this.atoms = atoms;
250 this.crystal = crystal;
251 this.use = use;
252 this.neighborLists = neighborLists;
253 this.x = x;
254 this.y = y;
255 this.z = z;
256 this.cut2 = cut2;
257 this.gradient = gradient;
258 this.grad = grad;
259 }
260
261
262 @Override
263 public void run() {
264 try {
265 int nAtoms = atoms.length;
266 execute(0, nAtoms - 1, dispersionLoop[getThreadIndex()]);
267 } catch (Exception e) {
268 String message =
269 "Fatal exception computing Dispersion energy in thread " + getThreadIndex() + "\n";
270 logger.log(Level.SEVERE, message, e);
271 }
272 }
273
274
275 @Override
276 public void start() {
277 sharedDispersion.set(0.0);
278 }
279
280
281
282
283
284
285 private class DispersionLoop extends IntegerForLoop {
286
287 private final double[] dx_local;
288 private double edisp;
289 private double r, r2, r3;
290 private double xr, yr, zr;
291 private int threadID;
292
293 DispersionLoop() {
294 dx_local = new double[3];
295 }
296
297 @Override
298 public void finish() {
299 sharedDispersion.addAndGet(edisp);
300 }
301
302 @Override
303 public void run(int lb, int ub) {
304 for (int i = lb; i <= ub; i++) {
305 if (!use[i]) {
306 continue;
307 }
308
309
310 VDWType type = atoms[i].getVDWType();
311 double epsi = type.wellDepth;
312 double rmini = type.radius / 2.0;
313 double cDisp = 0.0;
314 if (rmini > 0.0 && epsi > 0.0) {
315 double emixo = getCombinedEps(EPSO, epsi, RMINO, rmini, epsilonRule);
316 double rmixo = getCombinedRadius(RMINO, rmini, radiusRule);
317
318 double riO = rmixo / 2.0 + dispersionOffest;
319 cDisp = tailCorrection(riO, emixo, rmixo);
320 double emixh = getCombinedEps(EPSH, epsi, RMINH, rmini, epsilonRule);
321 double rmixh = getCombinedRadius(RMINH, rmini, radiusRule);
322
323 double riH = rmixh / 2.0 + dispersionOffest;
324 cDisp += 2.0 * tailCorrection(riH, emixh, rmixh);
325 cDisp = SLEVY * AWATER * cDisp;
326 }
327
328 edisp += cDisp;
329
330
331 double sum = 0.0;
332 final double xi = x[i];
333 final double yi = y[i];
334 final double zi = z[i];
335 int[] list = neighborLists[0][i];
336 for (int k : list) {
337 if (!use[k] || i == k) {
338 continue;
339 }
340 if (atoms[k].getVDWType().radius > 0.0) {
341 dx_local[0] = xi - x[k];
342 dx_local[1] = yi - y[k];
343 dx_local[2] = zi - z[k];
344 r2 = crystal.image(dx_local);
345 if (r2 > cut2) {
346 continue;
347 }
348 xr = dx_local[0];
349 yr = dx_local[1];
350 zr = dx_local[2];
351 r = sqrt(r2);
352 r3 = r * r2;
353
354 sum += removeSoluteDispersion(i, k);
355
356 xr = -xr;
357 yr = -yr;
358 zr = -zr;
359
360 sum += removeSoluteDispersion(k, i);
361 }
362 }
363
364 edisp -= SLEVY * AWATER * sum;
365 }
366 }
367
368 @Override
369 public void start() {
370 threadID = getThreadIndex();
371 edisp = 0;
372 }
373
374
375
376
377
378
379
380
381 private double removeSoluteDispersion(int i, int k) {
382
383
384 VDWType type = atoms[i].getVDWType();
385 double epsi = type.wellDepth;
386 double rmini = type.radius / 2.0;
387
388
389 double rmink = atoms[k].getVDWType().radius / 2.0;
390
391
392 double emixo = getCombinedEps(EPSO, epsi, RMINO, rmini, epsilonRule);
393 double rmixo = getCombinedRadius(RMINO, rmini, radiusRule);
394
395 double riO = rmixo / 2.0 + dispersionOffest;
396 double nO = 1.0;
397
398
399 double emixh = getCombinedEps(EPSH, epsi, RMINH, rmini, epsilonRule);
400 double rmixh = getCombinedRadius(RMINH, rmini, radiusRule);
401
402 double riH = rmixh / 2.0 + dispersionOffest;
403 double nH = 2.0;
404
405
406 double sk = (rmink + soluteOffset) * dispersionOverlapFactor;
407 return interact(i, k, nO, riO, sk, rmixo, emixo) + interact(i, k, nH, riH, sk, rmixh, emixh);
408 }
409
410
411
412
413
414
415
416
417
418
419
420
421
422 private double interact(
423 int i, int k, double factor, double ri, double sk, double rmix, double emix) {
424 double sum = 0.0;
425
426 if (ri < r + sk) {
427
428 double de = 0.0;
429 double sk2 = sk * sk;
430
431 double iStart = max(ri, r - sk);
432
433 double lik = iStart;
434
435
436 if (lik < rmix) {
437 double lik2 = lik * lik;
438 double lik3 = lik2 * lik;
439 double lik4 = lik3 * lik;
440
441 double uik = min(r + sk, rmix);
442 double uik2 = uik * uik;
443 double uik3 = uik2 * uik;
444 double uik4 = uik3 * uik;
445 sum = integralBeforeRMin(emix, r, r2, sk2, lik2, lik3, lik4, uik2, uik3, uik4);
446 if (gradient) {
447 de =
448 integralBeforeRminDerivative(
449 ri, emix, rmix, r, r2, r3, sk, sk2, lik, lik2, lik3, uik, uik2, uik3);
450 }
451 }
452
453 double uik = r + sk;
454
455 if (uik > rmix) {
456
457 lik = max(iStart, rmix);
458 double lik2 = lik * lik;
459 double lik3 = lik2 * lik;
460 double lik4 = lik3 * lik;
461 double lik5 = lik4 * lik;
462 double lik6 = lik5 * lik;
463 double lik10 = lik5 * lik5;
464 double lik11 = lik10 * lik;
465 double lik12 = lik11 * lik;
466 double uik2 = uik * uik;
467 double uik3 = uik2 * uik;
468 double uik4 = uik3 * uik;
469 double uik5 = uik4 * uik;
470 double uik10 = uik5 * uik5;
471 double uik11 = uik10 * uik;
472 double uik12 = uik11 * uik;
473 double rmix7 = pow(rmix, 7);
474 sum +=
475 integratlAfterRmin(
476 emix, rmix7, r, r2, sk2, lik, lik2, lik3, lik4, lik5, lik10, lik11, lik12, uik,
477 uik2, uik3, uik4, uik5, uik10, uik11, uik12);
478 if (gradient) {
479 double lik13 = lik12 * lik;
480 double uik6 = uik5 * uik;
481 double uik13 = uik12 * uik;
482 de +=
483 integratlAfterRminDerivative(
484 ri, emix, rmix, rmix7, iStart, r, r2, r3, sk, sk2, lik, lik2, lik3, lik5, lik6,
485 lik12, lik13, uik, uik2, uik3, uik6, uik13);
486 }
487 }
488
489 if (gradient) {
490 de = -de / r * factor * SLEVY * AWATER;
491 double dedx = de * xr;
492 double dedy = de * yr;
493 double dedz = de * zr;
494 grad.add(threadID, i, dedx, dedy, dedz);
495 grad.sub(threadID, k, dedx, dedy, dedz);
496 }
497 }
498 return factor * sum;
499 }
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516 private double integralBeforeRMin(
517 double eps,
518 double rij,
519 double rij2,
520 double rho2,
521 double lik2,
522 double lik3,
523 double lik4,
524 double uik2,
525 double uik3,
526 double uik4) {
527 return -eps
528 * (4.0
529 * PI
530 * (3.0 * (lik4 - uik4) - 8.0 * rij * (lik3 - uik3) + 6.0 * (rij2 - rho2) * (lik2 - uik2))
531 / (48.0 * rij));
532 }
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554 private double integralBeforeRminDerivative(
555 double ri,
556 double eps,
557 double rmin,
558 double rij,
559 double rij2,
560 double rij3,
561 double rho,
562 double rho2,
563 double lik,
564 double lik2,
565 double lik3,
566 double uik,
567 double uik2,
568 double uik3) {
569 double dl;
570 if (ri > rij - rho) {
571 dl = (-lik2 + 2.0 * rij2 + 2.0 * rho2) * lik2;
572 } else {
573 dl =
574 (-lik3 + 4.0 * lik2 * rij - 6.0 * lik * rij2 + 2.0 * lik * rho2 + 4.0 * rij3
575 - 4.0 * rij * rho2)
576 * lik;
577 }
578 double du;
579 if (rij + rho > rmin) {
580 du = -(-uik2 + 2.0 * rij2 + 2.0 * rho2) * uik2;
581 } else {
582 du =
583 -(-uik3 + 4.0 * uik2 * rij - 6.0 * uik * rij2 + 2.0 * uik * rho2 + 4.0 * rij3
584 - 4.0 * rij * rho2)
585 * uik;
586 }
587 return -eps * PI * (dl + du) / (4.0 * rij2);
588 }
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614 private double integratlAfterRmin(
615 double eps,
616 double rmin7,
617 double rij,
618 double rij2,
619 double rho2,
620 double lik,
621 double lik2,
622 double lik3,
623 double lik4,
624 double lik5,
625 double lik10,
626 double lik11,
627 double lik12,
628 double uik,
629 double uik2,
630 double uik3,
631 double uik4,
632 double uik5,
633 double uik10,
634 double uik11,
635 double uik12) {
636 double er7 = eps * rmin7;
637 double term = (15.0 * uik * lik * rij * (uik4 - lik4)
638 - 10.0 * uik2 * lik2 * (uik3 - lik3)
639 + 6.0 * (rho2 - rij2) * (uik5 - lik5)) / (120.0 * rij * lik5 * uik5);
640 double term2 = (120.0 * uik * lik * rij * (uik11 - lik11)
641 - 66.0 * uik2 * lik2 * (uik10 - lik10)
642 + 55.0 * (rho2 - rij2) * (uik12 - lik12)) / (2640.0 * rij * lik12 * uik12);
643 double idisp = -2.0 * er7 * term;
644 double irep = er7 * rmin7 * term2;
645 return 4.0 * PI * (irep + idisp);
646 }
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672 private double integratlAfterRminDerivative(
673 double ri,
674 double eps,
675 double rmin,
676 double rmin7,
677 double rmax,
678 double rij,
679 double rij2,
680 double rij3,
681 double rho,
682 double rho2,
683 double lik,
684 double lik2,
685 double lik3,
686 double lik5,
687 double lik6,
688 double lik12,
689 double lik13,
690 double uik,
691 double uik2,
692 double uik3,
693 double uik6,
694 double uik13) {
695 double er7 = eps * rmin7;
696 double lowerTerm = lik2 * rij + rij3 - rij * rho2;
697 double upperTerm = uik2 * rij + rij3 - rij * rho2;
698
699 double dl;
700 if (ri > rij - rho || rmax < rmin) {
701 dl = -(-5.0 * lik2 + 3.0 * rij2 + 3.0 * rho2) / lik5;
702 } else {
703 dl = (5.0 * lik3 - 33.0 * lik * rij2 - 3.0 * lik * rho2 + 15.0 * lowerTerm) / lik6;
704 }
705 double du = -(5.0 * uik3 - 33.0 * uik * rij2 - 3.0 * uik * rho2 + 15.0 * upperTerm) / uik6;
706 double de = -2.0 * PI * er7 * (dl + du) / (15.0 * rij2);
707
708 if (ri > rij - rho || rmax < rmin) {
709 dl = -(-6.0 * lik2 + 5.0 * rij2 + 5.0 * rho2) / lik12;
710 } else {
711 dl = (6.0 * lik3 - 125.0 * lik * rij2 - 5.0 * lik * rho2 + 60.0 * lowerTerm) / lik13;
712 }
713 du = -(6.0 * uik3 - 125.0 * uik * rij2 - 5.0 * uik * rho2 + 60.0 * upperTerm) / uik13;
714 de += PI * er7 * rmin7 * (dl + du) / (60.0 * rij2);
715
716 return de;
717 }
718 }
719 }