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.pme;
39
40 import edu.rit.pj.IntegerForLoop;
41 import edu.rit.pj.IntegerSchedule;
42 import edu.rit.pj.ParallelRegion;
43 import edu.rit.pj.ParallelTeam;
44 import ffx.crystal.Crystal;
45 import ffx.crystal.SymOp;
46 import ffx.numerics.atomic.AtomicDoubleArray3D;
47 import ffx.potential.bonded.Atom;
48 import ffx.potential.extended.ExtendedSystem;
49 import ffx.potential.nonbonded.ParticleMeshEwald;
50 import ffx.potential.parameters.ForceField;
51 import ffx.potential.parameters.MultipoleType;
52 import ffx.potential.parameters.MultipoleType.MultipoleFrameDefinition;
53 import ffx.potential.parameters.PolarizeType;
54
55 import java.util.List;
56 import java.util.logging.Level;
57 import java.util.logging.Logger;
58
59 import static ffx.potential.nonbonded.pme.AlchemicalParameters.AlchemicalMode.SCALE;
60 import static ffx.potential.parameters.MultipoleType.getRotationMatrix;
61 import static ffx.potential.parameters.MultipoleType.rotateMultipole;
62 import static ffx.potential.parameters.MultipoleType.t000;
63 import static ffx.potential.parameters.MultipoleType.t001;
64 import static ffx.potential.parameters.MultipoleType.t002;
65 import static ffx.potential.parameters.MultipoleType.t010;
66 import static ffx.potential.parameters.MultipoleType.t011;
67 import static ffx.potential.parameters.MultipoleType.t020;
68 import static ffx.potential.parameters.MultipoleType.t100;
69 import static ffx.potential.parameters.MultipoleType.t101;
70 import static ffx.potential.parameters.MultipoleType.t110;
71 import static ffx.potential.parameters.MultipoleType.t200;
72 import static java.lang.String.format;
73 import static org.apache.commons.math3.util.FastMath.max;
74
75
76
77
78
79
80
81
82 public class InitializationRegion extends ParallelRegion {
83
84 private static final Logger logger = Logger.getLogger(InitializationRegion.class.getName());
85
86 private final ParticleMeshEwald particleMeshEwald;
87
88
89
90
91
92 private final boolean rotateMultipoles;
93
94
95
96 private final boolean useCharges;
97
98
99
100 private final boolean useDipoles;
101
102
103
104 private final boolean useQuadrupoles;
105
106
107
108 private final InitializationLoop[] initializationLoop;
109
110
111
112 private final RotateMultipolesLoop[] rotateMultipolesLoop;
113
114
115
116 private boolean lambdaTerm;
117
118
119
120 private AlchemicalParameters alchemicalParameters;
121
122
123
124 private boolean esvTerm;
125
126
127
128 private ExtendedSystem esvSystem;
129
130
131
132 private Atom[] atoms;
133
134
135
136 private double[][][] coordinates;
137
138
139
140 private Crystal crystal;
141
142
143
144 private MultipoleFrameDefinition[] frame;
145
146
147
148 private int[][] axisAtom;
149
150
151
152 private double[][][] globalMultipole;
153
154
155
156 private double[][][] titrationMultipole;
157 private double[][][] tautomerMultipole;
158
159
160
161 private double[] polarizability;
162 private double[] titrationPolarizability;
163 private double[] tautomerPolarizability;
164 private double[] thole;
165 private double[] ipdamp;
166
167
168
169
170 private boolean[] use;
171
172
173
174 private int[][][] neighborLists;
175
176
177
178 private int[][][] realSpaceLists;
179
180 private int[][][] vaporLists;
181
182
183
184 private AtomicDoubleArray3D grad;
185
186
187
188 private AtomicDoubleArray3D torque;
189
190
191
192 private AtomicDoubleArray3D lambdaGrad;
193
194
195
196 private AtomicDoubleArray3D lambdaTorque;
197
198 public InitializationRegion(ParticleMeshEwald particleMeshEwald, int maxThreads,
199 ForceField forceField) {
200 initializationLoop = new InitializationLoop[maxThreads];
201 rotateMultipolesLoop = new RotateMultipolesLoop[maxThreads];
202 useCharges = forceField.getBoolean("USE_CHARGES", true);
203 useDipoles = forceField.getBoolean("USE_DIPOLES", true);
204 useQuadrupoles = forceField.getBoolean("USE_QUADRUPOLES", true);
205 rotateMultipoles = forceField.getBoolean("ROTATE_MULTIPOLES", true);
206 this.particleMeshEwald = particleMeshEwald;
207 }
208
209
210
211
212
213
214 public void executeWith(ParallelTeam parallelTeam) {
215 try {
216 parallelTeam.execute(this);
217 } catch (RuntimeException e) {
218 String message = "RuntimeException expanding coordinates and rotating multipoles.\n";
219 logger.log(Level.WARNING, message, e);
220 throw e;
221 } catch (Exception e) {
222 String message = "Fatal exception expanding coordinates and rotating multipoles.\n";
223 logger.log(Level.SEVERE, message, e);
224 }
225 }
226
227 public void init(
228 boolean lambdaTerm,
229 AlchemicalParameters alchemicalParameters,
230 ExtendedSystem esvSystem,
231 Atom[] atoms,
232 double[][][] coordinates,
233 Crystal crystal,
234 MultipoleFrameDefinition[] frame,
235 int[][] axisAtom,
236 double[][][] globalMultipole,
237 double[][][] titrationMultipole,
238 double[][][] tautomerMultipole,
239 double[] polarizability,
240 double[] titrationPolarizability,
241 double[] tautomerPolarizability,
242 double[] thole,
243 double[] ipdamp,
244 boolean[] use,
245 int[][][] neighborLists,
246 int[][][] realSpaceLists,
247 AtomicDoubleArray3D grad,
248 AtomicDoubleArray3D torque,
249 AtomicDoubleArray3D lambdaGrad,
250 AtomicDoubleArray3D lambdaTorque) {
251 this.lambdaTerm = lambdaTerm;
252 this.alchemicalParameters = alchemicalParameters;
253 this.esvSystem = esvSystem;
254 if (esvSystem != null) {
255 this.esvTerm = true;
256 }
257 this.atoms = atoms;
258 this.coordinates = coordinates;
259 this.crystal = crystal;
260 this.frame = frame;
261 this.axisAtom = axisAtom;
262 this.globalMultipole = globalMultipole;
263 this.titrationMultipole = titrationMultipole;
264 this.tautomerMultipole = tautomerMultipole;
265 this.polarizability = polarizability;
266 this.titrationPolarizability = titrationPolarizability;
267 this.tautomerPolarizability = tautomerPolarizability;
268 this.thole = thole;
269 this.ipdamp = ipdamp;
270 this.use = use;
271 this.neighborLists = neighborLists;
272 this.realSpaceLists = realSpaceLists;
273 this.vaporLists = alchemicalParameters.vaporLists;
274 this.grad = grad;
275 this.torque = torque;
276 this.lambdaGrad = lambdaGrad;
277 this.lambdaTorque = lambdaTorque;
278 }
279
280 @Override
281 public void run() {
282
283 int nAtoms = atoms.length;
284 int threadIndex = getThreadIndex();
285 if (initializationLoop[threadIndex] == null) {
286 initializationLoop[threadIndex] = new InitializationLoop();
287 rotateMultipolesLoop[threadIndex] = new RotateMultipolesLoop();
288 }
289 try {
290 execute(0, nAtoms - 1, initializationLoop[threadIndex]);
291 execute(0, nAtoms - 1, rotateMultipolesLoop[threadIndex]);
292 } catch (Exception e) {
293 String message = "Fatal exception initializing coordinates in thread: " + threadIndex + "\n";
294 logger.log(Level.SEVERE, message, e);
295 }
296 }
297
298 private class InitializationLoop extends IntegerForLoop {
299
300 private final double[] in = new double[3];
301 private final double[] out = new double[3];
302 private double[] x;
303 private double[] y;
304 private double[] z;
305 private int threadID;
306
307 @Override
308 public void run(int lb, int ub) {
309 grad.reset(threadID, lb, ub);
310 torque.reset(threadID, lb, ub);
311 if (lambdaTerm) {
312 lambdaGrad.reset(threadID, lb, ub);
313 lambdaTorque.reset(threadID, lb, ub);
314 }
315
316
317 for (int i = lb; i <= ub; i++) {
318 Atom atom = atoms[i];
319 x[i] = atom.getX();
320 y[i] = atom.getY();
321 z[i] = atom.getZ();
322 use[i] = atom.getUse();
323
324
325
326
327
328
329 int size = neighborLists[0][i].length;
330 if (vaporLists != null) {
331 size = max(size, vaporLists[0][i].length);
332 }
333 if (realSpaceLists[0][i] == null || realSpaceLists[0][i].length < size) {
334 realSpaceLists[0][i] = new int[size];
335 }
336 }
337
338
339 List<SymOp> symOps = crystal.spaceGroup.symOps;
340 int nSymm = symOps.size();
341 for (int iSymm = 1; iSymm < nSymm; iSymm++) {
342 SymOp symOp = symOps.get(iSymm);
343 double[] xs = coordinates[iSymm][0];
344 double[] ys = coordinates[iSymm][1];
345 double[] zs = coordinates[iSymm][2];
346 for (int i = lb; i <= ub; i++) {
347 in[0] = x[i];
348 in[1] = y[i];
349 in[2] = z[i];
350 crystal.applySymOp(in, out, symOp);
351 xs[i] = out[0];
352 ys[i] = out[1];
353 zs[i] = out[2];
354 int size = neighborLists[iSymm][i].length;
355 if (realSpaceLists[iSymm][i] == null || realSpaceLists[iSymm][i].length < size) {
356 realSpaceLists[iSymm][i] = new int[size];
357 }
358 }
359 }
360 }
361
362 @Override
363 public IntegerSchedule schedule() {
364 return IntegerSchedule.fixed();
365 }
366
367 @Override
368 public void start() {
369 x = coordinates[0][0];
370 y = coordinates[0][1];
371 z = coordinates[0][2];
372 threadID = getThreadIndex();
373 }
374 }
375
376 private class RotateMultipolesLoop extends IntegerForLoop {
377
378
379 private final double[] localOrigin = new double[3];
380 private final double[][] frameCoords = new double[4][3];
381 private final double[][] rotmat = new double[3][3];
382 private final double[] tempDipole = new double[3];
383 private final double[][] tempQuadrupole = new double[3][3];
384 private final double[] dipole = new double[3];
385 private final double[][] quadrupole = new double[3][3];
386
387 @Override
388 public void run(int lb, int ub) {
389 List<SymOp> symOps = crystal.spaceGroup.symOps;
390 int nSymm = symOps.size();
391 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
392 final double[] x = coordinates[iSymm][0];
393 final double[] y = coordinates[iSymm][1];
394 final double[] z = coordinates[iSymm][2];
395 for (int ii = lb; ii <= ub; ii++) {
396 Atom atom = atoms[ii];
397 double chargeScale = 1.0;
398 double dipoleScale = 1.0;
399 double quadrupoleScale = 1.0;
400 double polarizabilityScale = 1.0;
401 if (!useCharges) {
402 chargeScale = 0.0;
403 }
404 if (!useDipoles) {
405 dipoleScale = 0.0;
406 }
407 if (!useQuadrupoles) {
408 quadrupoleScale = 0.0;
409 }
410 if (!atom.getElectrostatics()) {
411 chargeScale = 0.0;
412 dipoleScale = 0.0;
413 quadrupoleScale = 0.0;
414 polarizabilityScale = 0.0;
415 }
416
417
418
419
420
421 if (alchemicalParameters.mode == SCALE && atom.applyLambda()) {
422 chargeScale *= alchemicalParameters.permLambda;
423 dipoleScale *= alchemicalParameters.permLambda;
424 quadrupoleScale *= alchemicalParameters.permLambda;
425 polarizabilityScale *= alchemicalParameters.polLambda;
426 }
427
428
429 MultipoleType multipoleType = particleMeshEwald.getMultipoleType(ii);
430 double[] in = multipoleType.getMultipole();
431
432 frame[ii] = multipoleType.frameDefinition;
433
434 axisAtom[ii] = atom.getAxisAtomIndices();
435
436 if (rotateMultipoles) {
437
438 localOrigin[0] = x[ii];
439 localOrigin[1] = y[ii];
440 localOrigin[2] = z[ii];
441
442
443 int[] referenceSites = axisAtom[ii];
444 int nSites = 0;
445 if (referenceSites != null) {
446 nSites = referenceSites.length;
447 }
448 for (int i = 0; i < nSites; i++) {
449 int index = referenceSites[i];
450 frameCoords[i][0] = x[index];
451 frameCoords[i][1] = y[index];
452 frameCoords[i][2] = z[index];
453 }
454
455
456 tempDipole[0] = in[t100];
457 tempDipole[1] = in[t010];
458 tempDipole[2] = in[t001];
459
460 tempQuadrupole[0][0] = in[t200];
461 tempQuadrupole[1][1] = in[t020];
462 tempQuadrupole[2][2] = in[t002];
463 tempQuadrupole[0][1] = in[t110];
464 tempQuadrupole[0][2] = in[t101];
465 tempQuadrupole[1][2] = in[t011];
466 tempQuadrupole[1][0] = in[t110];
467 tempQuadrupole[2][0] = in[t101];
468 tempQuadrupole[2][1] = in[t011];
469
470
471 boolean needsChiralInversion = false;
472
473
474
475
476
477
478
479
480
481
482
483
484
485 getRotationMatrix(frame[ii], localOrigin, frameCoords, rotmat);
486 rotateMultipole(rotmat, tempDipole, tempQuadrupole, dipole, quadrupole);
487 double[] out = globalMultipole[iSymm][ii];
488
489
490 out[t000] = in[0] * chargeScale;
491
492 out[t100] = dipole[0] * dipoleScale;
493 out[t010] = dipole[1] * dipoleScale;
494 out[t001] = dipole[2] * dipoleScale;
495
496 out[t200] = quadrupole[0][0] * quadrupoleScale;
497 out[t020] = quadrupole[1][1] * quadrupoleScale;
498 out[t002] = quadrupole[2][2] * quadrupoleScale;
499 out[t110] = quadrupole[0][1] * quadrupoleScale;
500 out[t101] = quadrupole[0][2] * quadrupoleScale;
501 out[t011] = quadrupole[1][2] * quadrupoleScale;
502
503 if (esvTerm && esvSystem.isTitrating(ii)) {
504 double[] esvMultipoleTitrDot = new double[10];
505 double[] esvMultipoleTautDot = new double[10];
506 double titrationLambda = esvSystem.getTitrationLambda(ii);
507 double tautomerLambda = esvSystem.getTautomerLambda(ii);
508 esvMultipoleTitrDot = esvSystem.getTitrationUtils()
509 .getMultipoleTitrationDeriv(atom, titrationLambda, tautomerLambda, esvMultipoleTitrDot);
510 esvMultipoleTautDot = esvSystem.getTitrationUtils()
511 .getMultipoleTautomerDeriv(atom, titrationLambda, tautomerLambda, esvMultipoleTautDot);
512 double tempCharge = esvMultipoleTitrDot[0];
513
514 tempDipole[0] = esvMultipoleTitrDot[t100];
515 tempDipole[1] = esvMultipoleTitrDot[t010];
516 tempDipole[2] = esvMultipoleTitrDot[t001];
517
518 tempQuadrupole[0][0] = esvMultipoleTitrDot[t200];
519 tempQuadrupole[1][1] = esvMultipoleTitrDot[t020];
520 tempQuadrupole[2][2] = esvMultipoleTitrDot[t002];
521 tempQuadrupole[0][1] = esvMultipoleTitrDot[t110];
522 tempQuadrupole[0][2] = esvMultipoleTitrDot[t101];
523 tempQuadrupole[1][2] = esvMultipoleTitrDot[t011];
524 tempQuadrupole[1][0] = esvMultipoleTitrDot[t110];
525 tempQuadrupole[2][0] = esvMultipoleTitrDot[t101];
526 tempQuadrupole[2][1] = esvMultipoleTitrDot[t011];
527 if (needsChiralInversion) {
528 tempDipole[1] = -tempDipole[1];
529 tempQuadrupole[0][1] = -tempQuadrupole[0][1];
530 tempQuadrupole[1][0] = -tempQuadrupole[1][0];
531 tempQuadrupole[1][2] = -tempQuadrupole[1][2];
532 tempQuadrupole[2][1] = -tempQuadrupole[2][1];
533 }
534 rotateMultipole(rotmat, tempDipole, tempQuadrupole, dipole, quadrupole);
535 out = titrationMultipole[iSymm][ii];
536 out[t000] = tempCharge * chargeScale;
537
538 out[t100] = dipole[0] * dipoleScale;
539 out[t010] = dipole[1] * dipoleScale;
540 out[t001] = dipole[2] * dipoleScale;
541
542 out[t200] = quadrupole[0][0] * quadrupoleScale;
543 out[t020] = quadrupole[1][1] * quadrupoleScale;
544 out[t002] = quadrupole[2][2] * quadrupoleScale;
545 out[t110] = quadrupole[0][1] * quadrupoleScale;
546 out[t101] = quadrupole[0][2] * quadrupoleScale;
547 out[t011] = quadrupole[1][2] * quadrupoleScale;
548
549 tempCharge = esvMultipoleTautDot[0];
550
551 tempDipole[0] = esvMultipoleTautDot[t100];
552 tempDipole[1] = esvMultipoleTautDot[t010];
553 tempDipole[2] = esvMultipoleTautDot[t001];
554
555 tempQuadrupole[0][0] = esvMultipoleTautDot[t200];
556 tempQuadrupole[1][1] = esvMultipoleTautDot[t020];
557 tempQuadrupole[2][2] = esvMultipoleTautDot[t002];
558 tempQuadrupole[0][1] = esvMultipoleTautDot[t110];
559 tempQuadrupole[0][2] = esvMultipoleTautDot[t101];
560 tempQuadrupole[1][2] = esvMultipoleTautDot[t011];
561 tempQuadrupole[1][0] = esvMultipoleTautDot[t110];
562 tempQuadrupole[2][0] = esvMultipoleTautDot[t101];
563 tempQuadrupole[2][1] = esvMultipoleTautDot[t011];
564 if (needsChiralInversion) {
565 tempDipole[1] = -tempDipole[1];
566 tempQuadrupole[0][1] = -tempQuadrupole[0][1];
567 tempQuadrupole[1][0] = -tempQuadrupole[1][0];
568 tempQuadrupole[1][2] = -tempQuadrupole[1][2];
569 tempQuadrupole[2][1] = -tempQuadrupole[2][1];
570 }
571 rotateMultipole(rotmat, tempDipole, tempQuadrupole, dipole, quadrupole);
572 out = tautomerMultipole[iSymm][ii];
573 out[t000] = tempCharge * chargeScale;
574
575 out[t100] = dipole[0] * dipoleScale;
576 out[t010] = dipole[1] * dipoleScale;
577 out[t001] = dipole[2] * dipoleScale;
578
579 out[t200] = quadrupole[0][0] * quadrupoleScale;
580 out[t020] = quadrupole[1][1] * quadrupoleScale;
581 out[t002] = quadrupole[2][2] * quadrupoleScale;
582 out[t110] = quadrupole[0][1] * quadrupoleScale;
583 out[t101] = quadrupole[0][2] * quadrupoleScale;
584 out[t011] = quadrupole[1][2] * quadrupoleScale;
585 }
586 } else {
587
588
589 double[] out = globalMultipole[iSymm][ii];
590 out[t000] = in[t000] * chargeScale;
591 out[t100] = in[t100] * dipoleScale;
592 out[t010] = in[t010] * dipoleScale;
593 out[t001] = in[t001] * dipoleScale;
594 out[t200] = in[t200] * quadrupoleScale;
595 out[t020] = in[t020] * quadrupoleScale;
596 out[t002] = in[t002] * quadrupoleScale;
597 out[t110] = in[t110] * quadrupoleScale;
598 out[t101] = in[t101] * quadrupoleScale;
599 out[t011] = in[t011] * quadrupoleScale;
600
601 if (esvTerm && esvSystem.isTitrating(ii)) {
602 double[] esvMultipoleTitrDot = new double[10];
603 double titrationLambda = esvSystem.getTitrationLambda(ii);
604 double tautomerLambda = esvSystem.getTautomerLambda(ii);
605 esvMultipoleTitrDot = esvSystem.getTitrationUtils()
606 .getMultipoleTitrationDeriv(atom, titrationLambda,
607 tautomerLambda, esvMultipoleTitrDot);
608 in = esvMultipoleTitrDot;
609 out = titrationMultipole[iSymm][ii];
610 out[t000] = in[t000] * chargeScale;
611 out[t100] = in[t100] * dipoleScale;
612 out[t010] = in[t010] * dipoleScale;
613 out[t001] = in[t001] * dipoleScale;
614 out[t200] = in[t200] * quadrupoleScale;
615 out[t020] = in[t020] * quadrupoleScale;
616 out[t002] = in[t002] * quadrupoleScale;
617 out[t110] = in[t110] * quadrupoleScale;
618 out[t101] = in[t101] * quadrupoleScale;
619 out[t011] = in[t011] * quadrupoleScale;
620
621 double[] esvMultipoleTautDot = new double[10];
622 esvMultipoleTautDot = esvSystem.getTitrationUtils()
623 .getMultipoleTautomerDeriv(atom, titrationLambda,
624 tautomerLambda, esvMultipoleTautDot);
625 in = esvMultipoleTautDot;
626 out = tautomerMultipole[iSymm][ii];
627 out[t000] = in[t000] * chargeScale;
628 out[t100] = in[t100] * dipoleScale;
629 out[t010] = in[t010] * dipoleScale;
630 out[t001] = in[t001] * dipoleScale;
631 out[t200] = in[t200] * quadrupoleScale;
632 out[t020] = in[t020] * quadrupoleScale;
633 out[t002] = in[t002] * quadrupoleScale;
634 out[t110] = in[t110] * quadrupoleScale;
635 out[t101] = in[t101] * quadrupoleScale;
636 out[t011] = in[t011] * quadrupoleScale;
637 }
638 }
639
640
641 PolarizeType polarizeType = particleMeshEwald.getPolarizeType(ii);
642 if (polarizeType != null) {
643 polarizability[ii] = polarizeType.polarizability * polarizabilityScale;
644 if (esvTerm && esvSystem.isTitrating(ii) && (esvSystem.isTitratingHydrogen(ii)
645 || esvSystem.isTitratingHeavy(ii))) {
646 titrationPolarizability[ii] = 0.0;
647 tautomerPolarizability[ii] = 0.0;
648 double titrationLambda = esvSystem.getTitrationLambda(ii);
649 double tautomerLambda = esvSystem.getTautomerLambda(ii);
650 titrationPolarizability[ii] = esvSystem.getTitrationUtils()
651 .getPolarizabilityTitrationDeriv(atom, titrationLambda, tautomerLambda);
652 tautomerPolarizability[ii] = esvSystem.getTitrationUtils()
653 .getPolarizabilityTautomerDeriv(atom, titrationLambda, tautomerLambda);
654 }
655 thole[ii] = polarizeType.thole;
656 ipdamp[ii] = polarizeType.pdamp;
657 if (!(ipdamp[ii] > 0.0)) {
658 ipdamp[ii] = Double.POSITIVE_INFINITY;
659 } else {
660 ipdamp[ii] = 1.0 / ipdamp[ii];
661 }
662 } else {
663 polarizability[ii] = 0.0;
664 thole[ii] = 0.0;
665 ipdamp[ii] = Double.POSITIVE_INFINITY;
666 }
667 }
668 }
669 }
670
671 @Override
672 public IntegerSchedule schedule() {
673 return IntegerSchedule.fixed();
674 }
675 }
676 }