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