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;
39
40 import edu.rit.pj.BarrierAction;
41 import edu.rit.pj.IntegerForLoop;
42 import edu.rit.pj.IntegerSchedule;
43 import edu.rit.pj.ParallelRegion;
44 import edu.rit.pj.ParallelTeam;
45 import edu.rit.pj.reduction.SharedDouble;
46 import edu.rit.pj.reduction.SharedInteger;
47 import ffx.crystal.Crystal;
48 import ffx.crystal.SymOp;
49 import ffx.numerics.atomic.AtomicDoubleArray.AtomicDoubleArrayImpl;
50 import ffx.numerics.atomic.AtomicDoubleArray3D;
51 import ffx.numerics.switching.MultiplicativeSwitch;
52 import ffx.potential.bonded.Atom;
53 import ffx.potential.bonded.Bond;
54 import ffx.potential.bonded.LambdaInterface;
55 import ffx.potential.extended.ExtendedSystem;
56 import ffx.potential.parameters.AtomType;
57 import ffx.potential.parameters.ForceField;
58 import ffx.potential.parameters.VDWType;
59 import ffx.utilities.FFXProperty;
60
61 import java.util.Arrays;
62 import java.util.List;
63 import java.util.logging.Level;
64 import java.util.logging.Logger;
65
66 import static ffx.potential.parameters.ForceField.toEnumForm;
67 import static ffx.utilities.PropertyGroup.NonBondedCutoff;
68 import static ffx.utilities.PropertyGroup.VanDerWaalsFunctionalForm;
69 import static java.lang.Double.isNaN;
70 import static java.lang.String.format;
71 import static java.util.Arrays.fill;
72 import static org.apache.commons.math3.util.FastMath.PI;
73 import static org.apache.commons.math3.util.FastMath.max;
74 import static org.apache.commons.math3.util.FastMath.min;
75 import static org.apache.commons.math3.util.FastMath.pow;
76 import static org.apache.commons.math3.util.FastMath.sqrt;
77
78
79
80
81
82
83
84
85
86
87 public class VanDerWaals implements MaskingInterface, LambdaInterface {
88
89 private static final Logger logger = Logger.getLogger(VanDerWaals.class.getName());
90 private static final byte HARD = 0;
91 private static final byte SOFT = 1;
92 private static final byte XX = 0;
93 private static final byte YY = 1;
94 private static final byte ZZ = 2;
95 private final boolean doLongRangeCorrection;
96
97
98
99 private final ParallelTeam parallelTeam;
100 private final int threadCount;
101 private final IntegerSchedule pairwiseSchedule;
102 private final SharedInteger sharedInteractions;
103 private final SharedDouble sharedEnergy;
104 private final SharedDouble shareddEdL;
105 private final SharedDouble sharedd2EdL2;
106 private final VanDerWaalsRegion vanDerWaalsRegion;
107 private final VanDerWaalsForm vdwForm;
108 @FFXProperty(name = "vdwindex", clazz = String.class, propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "class",
109 description = """
110 [CLASS / TYPE]
111 Specifies whether van der Waals parameters are provided for atom classes or atom types.
112 While most force fields are indexed by atom class, in OPLS models the vdW values are indexed by atom type.
113 The default in the absence of the vdwindex property is to index vdW parameters by atom class.
114 """)
115 private final String vdwIndex;
116 @FFXProperty(name = "vdw-taper", propertyGroup = NonBondedCutoff, defaultValue = "0.9", description = """
117 Allows modification of the cutoff windows for van der Waals potential energy interactions. "
118 The default value in the absence of the vdw-taper keyword is to begin the cutoff window
119 at 0.9 of the vdw cutoff distance.
120 """)
121 private final double vdwTaper;
122
123 private final NonbondedCutoff nonbondedCutoff;
124 private final MultiplicativeSwitch multiplicativeSwitch;
125
126
127
128 private Crystal crystal;
129
130
131
132 private Atom[] atoms;
133
134
135
136 private int[] molecule;
137
138
139
140 private boolean[] neuralNetwork;
141
142
143
144 private ForceField forceField;
145
146
147
148 private boolean[] use = null;
149
150
151
152 private int nAtoms;
153
154
155
156 private int nSymm;
157
158
159
160 private boolean gradient;
161 private boolean lambdaTerm;
162 private boolean esvTerm;
163 private boolean[] isSoft;
164
165
166
167
168
169
170
171
172
173 private boolean[][] softCore;
174
175
176
177 private boolean intermolecularSoftcore = false;
178
179
180
181
182
183
184 private boolean intramolecularSoftcore = false;
185
186
187
188 private double lambda = 1.0;
189
190
191
192 private double vdwLambdaEnd = 1.0;
193
194
195
196 private double vdwLambdaExponent = 3.0;
197
198
199
200 private double vdwLambdaAlpha = 0.25;
201
202
203
204
205 private LambdaFactors[] lambdaFactors = null;
206
207
208
209 private double sc1 = 0.0;
210
211
212
213 private double sc2 = 1.0;
214 private double dsc1dL = 0.0;
215 private double dsc2dL = 0.0;
216 private double d2sc1dL2 = 0.0;
217 private double d2sc2dL2 = 0.0;
218
219
220
221 private ExtendedSystem esvSystem;
222
223
224
225
226 private double[] coordinates;
227
228
229
230 private double[][] reduced;
231
232 private double[] reducedXYZ;
233
234
235
236 private int[][][] neighborLists;
237
238
239
240 private int[] atomClass;
241
242
243
244
245 private int[] reductionIndex;
246
247 private int[][] mask12;
248 private int[][] mask13;
249 private int[][] mask14;
250
251
252
253
254 private double[] reductionValue;
255
256 private boolean reducedHydrogen;
257 private double longRangeCorrection;
258 private AtomicDoubleArrayImpl atomicDoubleArrayImpl;
259
260
261
262 private AtomicDoubleArray3D grad;
263
264
265
266 private AtomicDoubleArray3D lambdaGrad;
267
268
269
270
271 private NeighborList neighborList;
272
273
274
275 private boolean forceNeighborListRebuild = true;
276
277 public VanDerWaals() {
278
279 doLongRangeCorrection = false;
280 parallelTeam = null;
281 threadCount = 0;
282 pairwiseSchedule = null;
283 sharedInteractions = null;
284 sharedEnergy = null;
285 shareddEdL = null;
286 sharedd2EdL2 = null;
287 vanDerWaalsRegion = null;
288 vdwForm = null;
289 nonbondedCutoff = null;
290 multiplicativeSwitch = null;
291 vdwIndex = null;
292 vdwTaper = VanDerWaalsForm.DEFAULT_VDW_TAPER;
293 }
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308 public VanDerWaals(
309 Atom[] atoms,
310 int[] molecule,
311 boolean[] neuralNetwork,
312 Crystal crystal,
313 ForceField forceField,
314 ParallelTeam parallelTeam,
315 double vdwCutoff,
316 double neighborListCutoff) {
317 this.atoms = atoms;
318 this.molecule = molecule;
319 this.neuralNetwork = neuralNetwork;
320 this.crystal = crystal;
321 this.parallelTeam = parallelTeam;
322 this.forceField = forceField;
323 nAtoms = atoms.length;
324 nSymm = crystal.spaceGroup.getNumberOfSymOps();
325 vdwForm = new VanDerWaalsForm(forceField);
326
327 vdwIndex = forceField.getString("VDWINDEX", "Class");
328 reducedHydrogen = forceField.getBoolean("REDUCE_HYDROGENS", true);
329
330
331 lambdaTerm = forceField.getBoolean("VDW_LAMBDATERM",
332 forceField.getBoolean("LAMBDATERM", false));
333 if (lambdaTerm) {
334 shareddEdL = new SharedDouble();
335 sharedd2EdL2 = new SharedDouble();
336 vdwLambdaAlpha = forceField.getDouble("VDW_LAMBDA_ALPHA", 0.25);
337 vdwLambdaExponent = forceField.getDouble("VDW_LAMBDA_EXPONENT", 3.0);
338 vdwLambdaEnd = forceField.getDouble("VDW_LAMBDA_END", 1.0);
339 if (vdwLambdaAlpha < 0.0) {
340 logger.warning(format(
341 " Invalid value %8.3g for vdw-lambda-alpha; must be greater than or equal to 0. Resetting to 0.25.",
342 vdwLambdaAlpha));
343 vdwLambdaAlpha = 0.25;
344 }
345 if (vdwLambdaExponent < 1.0) {
346 logger.warning(format(
347 " Invalid value %8.3g for vdw-lambda-exponent; must be greater than or equal to 1. Resetting to 3.",
348 vdwLambdaExponent));
349 vdwLambdaExponent = 3.0;
350 }
351
352 vdwLambdaEnd = forceField.getDouble("VDW_LAMBDA_END", 1.0);
353 if (vdwLambdaEnd < 0.0 || vdwLambdaEnd > 1.0) {
354 logger.warning(format(
355 " Invalid value %8.3g for vdw-lambda-end; must be between 0 and 1. Resetting to 1.", vdwLambdaEnd));
356 vdwLambdaEnd = 1.0;
357 }
358 intermolecularSoftcore = forceField.getBoolean("INTERMOLECULAR_SOFTCORE", false);
359 intramolecularSoftcore = forceField.getBoolean("INTRAMOLECULAR_SOFTCORE", false);
360 } else {
361 shareddEdL = null;
362 sharedd2EdL2 = null;
363 }
364
365
366 threadCount = parallelTeam.getThreadCount();
367 sharedInteractions = new SharedInteger();
368 sharedEnergy = new SharedDouble();
369 doLongRangeCorrection = forceField.getBoolean("VDW_CORRECTION", false);
370 vanDerWaalsRegion = new VanDerWaalsRegion();
371
372
373 atomicDoubleArrayImpl = AtomicDoubleArrayImpl.MULTI;
374 String value = forceField.getString("ARRAY_REDUCTION", "MULTI");
375 try {
376 atomicDoubleArrayImpl = AtomicDoubleArrayImpl.valueOf(toEnumForm(value));
377 } catch (Exception e) {
378 logger.info(format(
379 " Unrecognized ARRAY-REDUCTION %s; defaulting to %s", value, atomicDoubleArrayImpl));
380 }
381
382
383 initAtomArrays();
384
385
386
387
388
389
390 double taper = forceField.getDouble("VDW_TAPER", VanDerWaalsForm.DEFAULT_VDW_TAPER);
391 vdwTaper = taper * vdwCutoff;
392 double buff = 2.0;
393 nonbondedCutoff = new NonbondedCutoff(vdwCutoff, vdwTaper, buff);
394 multiplicativeSwitch = new MultiplicativeSwitch(vdwTaper, vdwCutoff);
395 neighborList = new NeighborList(crystal, atoms, neighborListCutoff, buff, parallelTeam);
396 pairwiseSchedule = neighborList.getPairwiseSchedule();
397 neighborLists = new int[nSymm][][];
398
399
400 buildNeighborList(atoms);
401
402
403 neighborList.setDisableUpdates(forceField.getBoolean("DISABLE_NEIGHBOR_UPDATES", false));
404
405 logger.info(toString());
406 }
407
408
409
410
411
412
413 @Override
414 public void applyMask(final int i, final boolean[] is14, final double[]... masks) {
415 double[] mask = masks[0];
416 var m12 = mask12[i];
417 for (int value : m12) {
418 mask[value] = vdwForm.scale12;
419 }
420 var m13 = mask13[i];
421 for (int value : m13) {
422 mask[value] = vdwForm.scale13;
423 }
424 var m14 = mask14[i];
425 for (int value : m14) {
426 mask[value] = vdwForm.scale14;
427 is14[value] = true;
428 }
429 }
430
431
432
433
434
435
436 public void attachExtendedSystem(ExtendedSystem system) {
437 if (system == null) {
438 logger.severe("Tried to attach null extended system.");
439 }
440 esvTerm = true;
441 esvSystem = system;
442
443
444 vdwLambdaAlpha = forceField.getDouble("VDW_LAMBDA_ALPHA", 0.05);
445 vdwLambdaExponent = forceField.getDouble("VDW_LAMBDA_EXPONENT", 1.0);
446 if (vdwLambdaExponent != 1.0) {
447 logger.warning(
448 format(
449 "ESVs are compatible only with a vdwLambdaExponent of unity!"
450 + " (found %g, resetting to 1.0)",
451 vdwLambdaExponent));
452 vdwLambdaExponent = 1.0;
453 }
454 if (vdwLambdaAlpha < 0.0) {
455 vdwLambdaAlpha = 0.05;
456 }
457
458 intermolecularSoftcore = forceField.getBoolean("INTERMOLECULAR_SOFTCORE", false);
459 intramolecularSoftcore = forceField.getBoolean("INTRAMOLECULAR_SOFTCORE", false);
460
461 Atom[] atomsExt = esvSystem.getExtendedAtoms();
462 int[] moleculeExt = esvSystem.getExtendedMolecule();
463
464
465 boolean[] nn = new boolean[atomsExt.length];
466 Arrays.fill(nn, false);
467 for (Atom a : atomsExt) {
468 if (a.isNeuralNetwork()) {
469 logger.severe(
470 "The combination of an extended system and neural networks are not supported.");
471 }
472 }
473
474 setAtoms(atomsExt, moleculeExt, nn);
475 }
476
477
478
479
480
481
482 public ExtendedSystem getExtendedSystem() {
483 return esvSystem;
484 }
485
486
487
488
489
490
491 public void destroy() throws Exception {
492 if (neighborList != null) {
493 neighborList.destroy();
494 }
495 }
496
497
498
499
500
501
502
503
504
505 public double energy(boolean gradient, boolean print) {
506 this.gradient = gradient;
507
508 try {
509 parallelTeam.execute(vanDerWaalsRegion);
510 } catch (Exception e) {
511 String message = " Fatal exception expanding coordinates.\n";
512 logger.log(Level.SEVERE, message, e);
513 }
514 return sharedEnergy.get();
515 }
516
517
518
519
520
521 public boolean getLambdaTerm() {
522 return lambdaTerm;
523 }
524
525
526
527
528 public boolean getIntramolecularSoftcore() {
529 return intramolecularSoftcore;
530 }
531
532
533
534
535
536
537 public double getAlpha() {
538 return vdwLambdaAlpha;
539 }
540
541
542
543
544
545
546 public double getBeta() {
547 return vdwLambdaExponent;
548 }
549
550
551
552
553
554
555
556 public double getBuffer() {
557 return nonbondedCutoff.buff;
558 }
559
560
561
562
563
564
565 public boolean getDoLongRangeCorrection() {
566 return doLongRangeCorrection;
567 }
568
569
570
571
572
573
574
575 public double getEnergy() {
576 return sharedEnergy.get();
577 }
578
579
580
581
582
583
584
585 public int getInteractions() {
586 return sharedInteractions.get();
587 }
588
589
590
591
592 @Override
593 public double getLambda() {
594 return lambda;
595 }
596
597
598
599
600 @Override
601 public void setLambda(double lambda) {
602 assert (lambda >= 0.0 && lambda <= 1.0);
603 if (!lambdaTerm) {
604 return;
605 }
606
607 if (lambda > vdwLambdaEnd) {
608 lambda = 1.0;
609 } else {
610 lambda = lambda / vdwLambdaEnd;
611 }
612 this.lambda = lambda;
613
614
615 sc1 = vdwLambdaAlpha * (1.0 - lambda) * (1.0 - lambda);
616
617 dsc1dL = -2.0 * vdwLambdaAlpha * (1.0 - lambda);
618
619 d2sc1dL2 = 2.0 * vdwLambdaAlpha;
620
621 sc2 = pow(lambda, vdwLambdaExponent);
622
623 dsc2dL = vdwLambdaExponent * pow(lambda, vdwLambdaExponent - 1.0);
624 if (vdwLambdaExponent >= 2.0) {
625
626 d2sc2dL2 = vdwLambdaExponent * (vdwLambdaExponent - 1.0) * pow(lambda, vdwLambdaExponent - 2.0);
627 } else {
628 d2sc2dL2 = 0.0;
629 }
630
631
632 if (!esvTerm) {
633 for (LambdaFactors lf : lambdaFactors) {
634 lf.setFactors();
635 }
636 }
637
638 initSoftCore();
639
640
641 if (doLongRangeCorrection) {
642 longRangeCorrection = computeLongRangeCorrection();
643 } else {
644 longRangeCorrection = 0.0;
645 }
646 }
647
648
649
650
651
652
653 public int[][] getMask12() {
654 return mask12;
655 }
656
657
658
659
660
661
662 public int[][] getMask13() {
663 return mask13;
664 }
665
666
667
668
669
670
671 public int[][] getMask14() {
672 return mask14;
673 }
674
675
676
677
678
679
680 public NeighborList getNeighborList() {
681 return neighborList;
682 }
683
684
685
686
687
688
689 public int[][][] getNeighborLists() {
690 return neighborLists;
691 }
692
693
694
695
696
697
698 public NonbondedCutoff getNonbondedCutoff() {
699 return nonbondedCutoff;
700 }
701
702
703
704
705
706
707 public int[] getReductionIndex() {
708 return reductionIndex;
709 }
710
711
712
713
714
715
716 public VanDerWaalsForm getVDWForm() {
717 return vdwForm;
718 }
719
720
721
722
723 @Override
724 public double getd2EdL2() {
725 if (sharedd2EdL2 == null || !lambdaTerm) {
726 return 0.0;
727 }
728 return sharedd2EdL2.get();
729 }
730
731
732
733
734 @Override
735 public double getdEdL() {
736 if (shareddEdL == null || !lambdaTerm) {
737 return 0.0;
738 }
739 return shareddEdL.get();
740 }
741
742
743
744
745 @Override
746 public void getdEdXdL(double[] lambdaGradient) {
747 if (lambdaGrad == null || !lambdaTerm) {
748 return;
749 }
750 int index = 0;
751 for (int i = 0; i < nAtoms; i++) {
752 if (atoms[i].isActive()) {
753 lambdaGradient[index++] += lambdaGrad.getX(i);
754 lambdaGradient[index++] += lambdaGrad.getY(i);
755 lambdaGradient[index++] += lambdaGrad.getZ(i);
756 }
757 }
758 }
759
760
761
762
763
764
765 @Override
766 public void removeMask(final int i, final boolean[] is14, final double[]... masks) {
767 double[] mask = masks[0];
768 var m12 = mask12[i];
769 for (int value : m12) {
770 mask[value] = 1.0;
771 }
772 var m13 = mask13[i];
773 for (int value : m13) {
774 mask[value] = 1.0;
775 }
776 var m14 = mask14[i];
777 for (int value : m14) {
778 mask[value] = 1.0;
779 is14[value] = false;
780 }
781 }
782
783
784
785
786
787
788
789
790
791 public void setAtoms(Atom[] atoms, int[] molecule, boolean[] neuralNetwork) {
792 this.atoms = atoms;
793 this.nAtoms = atoms.length;
794 this.molecule = molecule;
795 this.neuralNetwork = neuralNetwork;
796
797 if (nAtoms != molecule.length) {
798 logger.warning("Atom and molecule arrays are of different lengths.");
799 throw new IllegalArgumentException();
800 }
801
802 initAtomArrays();
803 buildNeighborList(atoms);
804 }
805
806
807
808
809
810
811
812
813 public void setCrystal(Crystal crystal) {
814 if (this.crystal.equals(crystal)) {
815 return;
816 }
817 this.crystal = crystal;
818 int newNSymm = crystal.spaceGroup.getNumberOfSymOps();
819 if (nSymm != newNSymm) {
820 nSymm = newNSymm;
821
822 if (reduced == null || reduced.length < nSymm) {
823 reduced = new double[nSymm][nAtoms * 3];
824 reducedXYZ = reduced[0];
825 neighborLists = new int[nSymm][][];
826 }
827 }
828 neighborList.setCrystal(crystal);
829 forceNeighborListRebuild = true;
830 try {
831 parallelTeam.execute(vanDerWaalsRegion);
832 } catch (Exception e) {
833 String message = " Fatal exception expanding coordinates.\n";
834 logger.log(Level.SEVERE, message, e);
835 }
836 }
837
838
839
840
841 @Override
842 public String toString() {
843 StringBuffer sb = new StringBuffer("\n Van der Waals\n");
844 if (multiplicativeSwitch.getSwitchStart() != Double.POSITIVE_INFINITY) {
845 sb.append(format(" Switch Start: %6.3f (A)\n",
846 multiplicativeSwitch.getSwitchStart()));
847 sb.append(format(" Cut-Off: %6.3f (A)",
848 multiplicativeSwitch.getSwitchEnd()));
849 } else {
850 sb.append(" Cut-Off: NONE");
851 }
852
853 sb.append(format("\n Long-Range Correction: %6B", doLongRangeCorrection));
854 if (!reducedHydrogen) {
855 sb.append(format("\n Reduce Hydrogen: %6B", reducedHydrogen));
856 }
857 if (lambdaTerm) {
858 sb.append("\n Alchemical Parameters\n");
859 sb.append(format(" Softcore Alpha: %5.3f\n", vdwLambdaAlpha));
860 sb.append(format(" Lambda Exponent: %5.3f\n", vdwLambdaExponent));
861 sb.append(format(" Lambda End: %5.3f", vdwLambdaEnd));
862 }
863 return sb.toString();
864 }
865
866
867
868
869 private void initAtomArrays() {
870 if (esvTerm) {
871 atoms = esvSystem.getExtendedAtoms();
872 nAtoms = atoms.length;
873 }
874 if (atomClass == null || nAtoms > atomClass.length || lambdaTerm || esvTerm) {
875 atomClass = new int[nAtoms];
876 coordinates = new double[nAtoms * 3];
877 reduced = new double[nSymm][nAtoms * 3];
878 reducedXYZ = reduced[0];
879 reductionIndex = new int[nAtoms];
880 reductionValue = new double[nAtoms];
881 mask12 = new int[nAtoms][];
882 mask13 = new int[nAtoms][];
883 mask14 = new int[nAtoms][];
884 use = new boolean[nAtoms];
885 isSoft = new boolean[nAtoms];
886 softCore = new boolean[2][nAtoms];
887 grad = new AtomicDoubleArray3D(atomicDoubleArrayImpl, nAtoms, threadCount);
888 if (lambdaTerm) {
889 lambdaGrad = new AtomicDoubleArray3D(atomicDoubleArrayImpl, nAtoms, threadCount);
890 } else {
891 lambdaGrad = null;
892 }
893 }
894
895
896 fill(use, true);
897 fill(isSoft, false);
898 fill(softCore[HARD], false);
899 fill(softCore[SOFT], false);
900
901 lambdaFactors = new LambdaFactors[threadCount];
902 for (int i = 0; i < threadCount; i++) {
903 if (lambdaTerm) {
904 lambdaFactors[i] = new LambdaFactorsOST();
905 } else {
906 lambdaFactors[i] = new LambdaFactors();
907 }
908 }
909
910 for (int i = 0; i < nAtoms; i++) {
911 Atom ai = atoms[i];
912 assert (i == ai.getXyzIndex() - 1);
913 double[] xyz = ai.getXYZ(null);
914 int i3 = i * 3;
915 coordinates[i3 + XX] = xyz[XX];
916 coordinates[i3 + YY] = xyz[YY];
917 coordinates[i3 + ZZ] = xyz[ZZ];
918
919 VDWType vdwType = ai.getVDWType();
920 if (vdwType == null) {
921
922 AtomType atomType = ai.getAtomType();
923 if (atomType == null) {
924 logger.severe(ai.toString());
925 return;
926 }
927
928 if (vdwIndex.equalsIgnoreCase("Type")) {
929 atomClass[i] = atomType.type;
930 } else {
931 atomClass[i] = atomType.atomClass;
932 }
933 vdwType = forceField.getVDWType(Integer.toString(atomClass[i]));
934
935 if (vdwType == null) {
936 logger.info(" No VdW type for atom class " + atomClass[i]);
937 logger.severe(" No VdW type for atom " + ai);
938 return;
939 }
940 ai.setVDWType(vdwType);
941 }
942
943 atomClass[i] = vdwType.atomClass;
944
945 List<Bond> bonds = ai.getBonds();
946 int numBonds = bonds.size();
947 if (reducedHydrogen && vdwType.reductionFactor > 0.0 && numBonds == 1) {
948 Bond bond = bonds.get(0);
949 Atom heavyAtom = bond.get1_2(ai);
950
951 reductionIndex[i] = heavyAtom.getIndex() - 1;
952 reductionValue[i] = vdwType.reductionFactor;
953 } else {
954 reductionIndex[i] = i;
955 reductionValue[i] = 0.0;
956 }
957
958
959 List<Atom> n12 = ai.get12List();
960 mask12[i] = new int[n12.size()];
961 int j = 0;
962 for (Atom a12 : n12) {
963 mask12[i][j++] = a12.getIndex() - 1;
964 }
965
966
967 List<Atom> n13 = ai.get13List();
968 mask13[i] = new int[n13.size()];
969 j = 0;
970 for (Atom a13 : n13) {
971 mask13[i][j++] = a13.getIndex() - 1;
972 }
973
974
975 List<Atom> n14 = ai.get14List();
976 mask14[i] = new int[n14.size()];
977 j = 0;
978 for (Atom a14 : n14) {
979 mask14[i][j++] = a14.getIndex() - 1;
980 }
981 }
982 }
983
984
985
986
987
988
989 private void buildNeighborList(Atom[] atoms) {
990 neighborList.setAtoms(atoms);
991 forceNeighborListRebuild = true;
992 try {
993 parallelTeam.execute(vanDerWaalsRegion);
994 } catch (Exception e) {
995 String message = " Fatal exception expanding coordinates.\n";
996 logger.log(Level.SEVERE, message, e);
997 }
998 forceNeighborListRebuild = false;
999 }
1000
1001
1002
1003
1004
1005
1006
1007
1008 private double computeLongRangeCorrection() {
1009
1010 if (esvTerm) {
1011 throw new UnsupportedOperationException();
1012 }
1013
1014
1015 if (crystal.aperiodic()) {
1016 return 0.0;
1017 }
1018
1019
1020
1021
1022
1023
1024 int stepsPerAngstrom = 2;
1025 double range = 100.0;
1026 int nDelta = (int) ((double) stepsPerAngstrom * (range - nonbondedCutoff.cut));
1027 double rDelta = (range - nonbondedCutoff.cut) / (double) nDelta;
1028 double offset = nonbondedCutoff.cut - 0.5 * rDelta;
1029 double oneMinLambda = 1.0 - lambda;
1030
1031
1032 int maxClass = vdwForm.maxClass;
1033 int[] radCount = new int[maxClass + 1];
1034 int[] softRadCount = new int[maxClass + 1];
1035 fill(radCount, 0);
1036 fill(softRadCount, 0);
1037 for (int i = 0; i < nAtoms; i++) {
1038 radCount[atomClass[i]]++;
1039 if (isSoft[i]) {
1040 softRadCount[atomClass[i]]++;
1041 }
1042 }
1043
1044 double total = 0.0;
1045
1046 for (int i = 1; i < maxClass + 1; i++) {
1047 for (int j = i; j < maxClass + 1; j++) {
1048 if (radCount[i] == 0 || radCount[j] == 0) {
1049 continue;
1050 }
1051 double irv = vdwForm.getCombinedInverseRmin(i, j);
1052 double ev = vdwForm.getCombinedEps(i, j);
1053 if (isNaN(irv) || irv == 0 || isNaN(ev)) {
1054 continue;
1055 }
1056 double sume = 0.0;
1057 for (int k = 1; k <= nDelta; k++) {
1058 double r = offset + (double) k * rDelta;
1059 double r2 = r * r;
1060 final double rho = r * irv;
1061 final double rho3 = rho * rho * rho;
1062 final double rhod = rho + vdwForm.delta;
1063 final double rhod3 = rhod * rhod * rhod;
1064 double t1, t2;
1065 switch (vdwForm.vdwType) {
1066 case LENNARD_JONES -> {
1067 final double rho6 = rho3 * rho3;
1068 final double rhod6 = rhod3 * rhod3;
1069 t1 = vdwForm.t1n / rhod6;
1070 t2 = vdwForm.gamma1 / (rho6 + vdwForm.gamma) - 2.0;
1071 }
1072 case BUFFERED_14_7 -> {
1073 final double rho7 = rho3 * rho3 * rho;
1074 final double rhod7 = rhod3 * rhod3 * rhod;
1075 t1 = vdwForm.t1n / rhod7;
1076 t2 = vdwForm.gamma1 / (rho7 + vdwForm.gamma) - 2.0;
1077 }
1078 default -> {
1079
1080 final double rhoN = pow(rho, vdwForm.dispersivePower);
1081 final double rhodN = pow(rhod, vdwForm.dispersivePower);
1082 t1 = vdwForm.t1n / rhodN;
1083 t2 = vdwForm.gamma1 / (rhoN + vdwForm.gamma) - 2.0;
1084 }
1085 }
1086 final double eij = ev * t1 * t2;
1087
1088
1089
1090
1091
1092 double taper = 1.0;
1093 if (r2 < nonbondedCutoff.off2) {
1094 double r3 = r * r2;
1095 double r4 = r2 * r2;
1096 double r5 = r2 * r3;
1097 taper = multiplicativeSwitch.taper(r, r2, r3, r4, r5);
1098 taper = 1.0 - taper;
1099 }
1100
1101 double jacobian = 4.0 * PI * r2;
1102 double e = jacobian * eij * taper;
1103 if (j != i) {
1104 sume += e;
1105 } else {
1106 sume += 0.5 * e;
1107 }
1108 }
1109 double trapezoid = rDelta * sume;
1110
1111
1112 total += radCount[i] * radCount[j] * trapezoid;
1113
1114 if (lambda < 1.0) {
1115 total -= (softRadCount[i] * radCount[j] + (radCount[i] - softRadCount[i]) * softRadCount[j])
1116 * oneMinLambda * trapezoid;
1117 }
1118 }
1119 }
1120
1121
1122 Crystal unitCell = crystal.getUnitCell();
1123 double asymmetricUnitVolume = unitCell.volume / unitCell.getNumSymOps();
1124 total /= asymmetricUnitVolume;
1125 logger.fine(format(" Long-range vdW correction: %16.8f", total));
1126 return total;
1127 }
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139 private void log(int i, int k, double minr, double r, double eij) {
1140 Atom ai = atoms[i];
1141 Atom ak = atoms[k];
1142 logger.info(format("VDW %6d-%s %d %6d-%s %d %10.4f %10.4f %10.4f",
1143 ai.getIndex(), ai.getAtomType().name, ai.getVDWType().atomClass,
1144 ak.getIndex(), ak.getAtomType().name, ak.getVDWType().atomClass,
1145 minr, r, eij));
1146 logger.info(format(" %d %s\n %d %s",
1147 i + 1, Arrays.toString(ai.getXYZ(null)),
1148 k + 1, Arrays.toString(ak.getXYZ(null))));
1149 }
1150
1151 private void initSoftCore() {
1152
1153 boolean rebuild = false;
1154
1155 for (int i = 0; i < nAtoms; i++) {
1156 boolean soft = atoms[i].applyLambda();
1157 if (soft != isSoft[i]) {
1158 isSoft[i] = soft;
1159 rebuild = true;
1160 }
1161 }
1162
1163 if (!rebuild) {
1164 return;
1165 }
1166
1167
1168 for (int i = 0; i < nAtoms; i++) {
1169 if (isSoft[i]) {
1170
1171 softCore[HARD][i] = true;
1172
1173 softCore[SOFT][i] = false;
1174 } else {
1175
1176 softCore[HARD][i] = false;
1177
1178 softCore[SOFT][i] = true;
1179 }
1180 }
1181 }
1182
1183
1184
1185
1186
1187
1188
1189 public static class LambdaFactors {
1190
1191 double sc1 = 0.0;
1192 double dsc1dL = 0.0;
1193 double d2sc1dL2 = 0.0;
1194 double sc2 = 1.0;
1195 double dsc2dL = 0.0;
1196 double d2sc2dL2 = 0.0;
1197
1198
1199
1200
1201 public void setFactors() {
1202 }
1203 }
1204
1205 public class LambdaFactorsOST extends LambdaFactors {
1206
1207 @Override
1208 public void setFactors() {
1209 sc1 = VanDerWaals.this.sc1;
1210 dsc1dL = VanDerWaals.this.dsc1dL;
1211 d2sc1dL2 = VanDerWaals.this.d2sc1dL2;
1212 sc2 = VanDerWaals.this.sc2;
1213 dsc2dL = VanDerWaals.this.dsc2dL;
1214 d2sc2dL2 = VanDerWaals.this.d2sc2dL2;
1215 }
1216 }
1217
1218 private class VanDerWaalsRegion extends ParallelRegion {
1219
1220 private final InitializationLoop[] initializationLoop;
1221 private final ExpandLoop[] expandLoop;
1222 private final VanDerWaalsLoop[] vanDerWaalsLoop;
1223 private final ReductionLoop[] reductionLoop;
1224 private final NeighborListBarrier neighborListAction;
1225
1226
1227
1228
1229 private long initLoopTotalTime, vdWLoopTotalTime, reductionLoopTimeTotal;
1230 private long neighborListTotalTime, vdwTimeTotal;
1231
1232 VanDerWaalsRegion() {
1233 initializationLoop = new InitializationLoop[threadCount];
1234 expandLoop = new ExpandLoop[threadCount];
1235 vanDerWaalsLoop = new VanDerWaalsLoop[threadCount];
1236 reductionLoop = new ReductionLoop[threadCount];
1237 neighborListAction = new NeighborListBarrier();
1238 }
1239
1240 @Override
1241 public void finish() {
1242 forceNeighborListRebuild = false;
1243 vdwTimeTotal += System.nanoTime();
1244
1245 if (logger.isLoggable(Level.FINE)) {
1246 logger.fine(format("\n Neighbor-List: %7.4f (sec)", neighborListTotalTime * 1e-9));
1247 logger.fine(format(" Van der Waals: %7.4f (sec)", (vdwTimeTotal - neighborListTotalTime) * 1e-9));
1248 logger.fine(" Thread Init Energy Reduce Total Counts");
1249 long initMax = 0;
1250 long vdwMax = 0;
1251 long reductionMax = 0;
1252 long initMin = Long.MAX_VALUE;
1253 long vdwMin = Long.MAX_VALUE;
1254 long reductionMin = Long.MAX_VALUE;
1255 int countMin = Integer.MAX_VALUE;
1256 int countMax = 0;
1257 for (int i = 0; i < threadCount; i++) {
1258 int count = vanDerWaalsLoop[i].getCount();
1259 long initTime = initializationLoop[i].time + expandLoop[i].time;
1260 long vdWTime = vanDerWaalsLoop[i].time;
1261 long reduceTime = reductionLoop[i].time;
1262 long totalTime = initTime + vdWTime + reduceTime;
1263 logger.fine(format(" %3d %7.4f %7.4f %7.4f %7.4f %10d", i,
1264 initTime * 1e-9, vdWTime * 1e-9, reduceTime * 1e-9, totalTime * 1e-9, count));
1265 initMax = max(initTime, initMax);
1266 vdwMax = max(vdWTime, vdwMax);
1267 reductionMax = max(reduceTime, reductionMax);
1268 countMax = max(countMax, count);
1269 initMin = min(initTime, initMin);
1270 vdwMin = min(vdWTime, vdwMin);
1271 reductionMin = min(reduceTime, reductionMin);
1272 countMin = min(countMin, count);
1273 }
1274 long totalMin = initMin + vdwMin + reductionMin;
1275 long totalMax = initMax + vdwMax + reductionMax;
1276 long totalActual = initLoopTotalTime + vdWLoopTotalTime + reductionLoopTimeTotal;
1277 logger.fine(format(" Min %7.4f %7.4f %7.4f %7.4f %10d",
1278 initMin * 1e-9, vdwMin * 1e-9, reductionMin * 1e-9, totalMin * 1e-9, countMin));
1279 logger.fine(format(" Max %7.4f %7.4f %7.4f %7.4f %10d",
1280 initMax * 1e-9, vdwMax * 1e-9, reductionMax * 1e-9, totalMax * 1e-9, countMax));
1281 logger.fine(format(" Delta %7.4f %7.4f %7.4f %7.4f %10d",
1282 (initMax - initMin) * 1e-9, (vdwMax - vdwMin) * 1e-9,
1283 (reductionMax - reductionMin) * 1e-9, (totalMax - totalMin) * 1e-9,
1284 (countMax - countMin)));
1285 logger.fine(format(" Actual %7.4f %7.4f %7.4f %7.4f %10d\n",
1286 initLoopTotalTime * 1e-9, vdWLoopTotalTime * 1e-9, reductionLoopTimeTotal * 1e-9,
1287 totalActual * 1e-9, sharedInteractions.get()));
1288 }
1289 }
1290
1291 @Override
1292 public void run() throws Exception {
1293 int threadIndex = getThreadIndex();
1294
1295
1296 if (initializationLoop[threadIndex] == null) {
1297 initializationLoop[threadIndex] = new InitializationLoop();
1298 expandLoop[threadIndex] = new ExpandLoop();
1299 vanDerWaalsLoop[threadIndex] = new VanDerWaalsLoop();
1300 reductionLoop[threadIndex] = new ReductionLoop();
1301 }
1302
1303
1304 try {
1305 if (threadIndex == 0) {
1306 initLoopTotalTime = -System.nanoTime();
1307 }
1308 execute(0, nAtoms - 1, initializationLoop[threadIndex]);
1309 execute(0, nAtoms - 1, expandLoop[threadIndex]);
1310 if (threadIndex == 0) {
1311 initLoopTotalTime += System.nanoTime();
1312 }
1313 } catch (RuntimeException ex) {
1314 logger.warning("Runtime exception expanding coordinates in thread: " + threadIndex);
1315 throw ex;
1316 } catch (Exception e) {
1317 String message = "Fatal exception expanding coordinates in thread: " + threadIndex + "\n";
1318 logger.log(Level.SEVERE, message, e);
1319 }
1320
1321
1322 barrier(neighborListAction);
1323 if (forceNeighborListRebuild) {
1324 return;
1325 }
1326
1327
1328 try {
1329 if (threadIndex == 0) {
1330 vdWLoopTotalTime = -System.nanoTime();
1331 }
1332 execute(0, nAtoms - 1, vanDerWaalsLoop[threadIndex]);
1333 if (threadIndex == 0) {
1334 vdWLoopTotalTime += System.nanoTime();
1335 }
1336 } catch (RuntimeException ex) {
1337 logger.warning("Runtime exception evaluating van der Waals energy in thread: " + threadIndex);
1338 throw ex;
1339 } catch (Exception e) {
1340 String message = "Fatal exception evaluating van der Waals energy in thread: " + threadIndex + "\n";
1341 logger.log(Level.SEVERE, message, e);
1342 }
1343
1344
1345 if (gradient || lambdaTerm) {
1346 try {
1347 if (threadIndex == 0) {
1348 reductionLoopTimeTotal = -System.nanoTime();
1349 }
1350 execute(0, nAtoms - 1, reductionLoop[threadIndex]);
1351 if (threadIndex == 0) {
1352 reductionLoopTimeTotal += System.nanoTime();
1353 }
1354 } catch (RuntimeException ex) {
1355 logger.warning(
1356 "Runtime exception reducing van der Waals gradient in thread: " + threadIndex);
1357 throw ex;
1358 } catch (Exception e) {
1359 String message =
1360 "Fatal exception reducing van der Waals gradient in thread: " + threadIndex + "\n";
1361 logger.log(Level.SEVERE, message, e);
1362 }
1363 }
1364 }
1365
1366
1367
1368
1369
1370
1371 @Override
1372 public void start() {
1373
1374 vdwTimeTotal = -System.nanoTime();
1375
1376
1377 if (doLongRangeCorrection) {
1378 longRangeCorrection = computeLongRangeCorrection();
1379 sharedEnergy.set(longRangeCorrection);
1380 } else {
1381 sharedEnergy.set(0.0);
1382 }
1383 sharedInteractions.set(0);
1384 if (lambdaTerm) {
1385 shareddEdL.set(0.0);
1386 sharedd2EdL2.set(0.0);
1387 }
1388 if (esvTerm) {
1389 esvSystem.initEsvVdw();
1390 lambdaFactors = new LambdaFactors[threadCount];
1391 for (int i = 0; i < threadCount; i++) {
1392 lambdaFactors[i] = new LambdaFactors();
1393 }
1394 }
1395
1396 grad.alloc(nAtoms);
1397 if (lambdaTerm) {
1398 lambdaGrad.alloc(nAtoms);
1399 }
1400 }
1401
1402
1403
1404
1405 private class InitializationLoop extends IntegerForLoop {
1406
1407 private int threadID;
1408 protected long time;
1409
1410 @Override
1411 public void run(int lb, int ub) {
1412 for (int i = lb, i3 = 3 * lb; i <= ub; i++, i3 += 3) {
1413 Atom atom = atoms[i];
1414 coordinates[i3 + XX] = atom.getX();
1415 coordinates[i3 + YY] = atom.getY();
1416 coordinates[i3 + ZZ] = atom.getZ();
1417 use[i] = atom.getUse();
1418
1419
1420 VDWType vdwType = atom.getVDWType();
1421 if (vdwType == null) {
1422 logger.severe(" No VdW type for atom " + atom);
1423 return;
1424 }
1425
1426
1427 atomClass[i] = vdwType.atomClass;
1428
1429
1430 List<Bond> bonds = atom.getBonds();
1431 int numBonds = bonds.size();
1432 if (reducedHydrogen && vdwType.reductionFactor > 0.0 && numBonds == 1) {
1433 Bond bond = bonds.get(0);
1434 Atom heavyAtom = bond.get1_2(atom);
1435
1436 reductionIndex[i] = heavyAtom.getIndex() - 1;
1437 reductionValue[i] = vdwType.reductionFactor;
1438 } else {
1439 reductionIndex[i] = i;
1440 reductionValue[i] = 0.0;
1441 }
1442
1443
1444 List<Atom> n12 = atom.get12List();
1445 if (mask12[i] == null || mask12[i].length != n12.size()) {
1446 mask12[i] = new int[n12.size()];
1447 }
1448 int j = 0;
1449 for (Atom a12 : n12) {
1450 mask12[i][j++] = a12.getIndex() - 1;
1451 }
1452
1453
1454 List<Atom> n13 = atom.get13List();
1455 if (mask13[i] == null || mask13[i].length != n13.size()) {
1456 mask13[i] = new int[n13.size()];
1457 }
1458 j = 0;
1459 for (Atom a13 : n13) {
1460 mask13[i][j++] = a13.getIndex() - 1;
1461 }
1462
1463
1464 List<Atom> n14 = atom.get14List();
1465 if (mask14[i] == null || mask14[i].length != n14.size()) {
1466 mask14[i] = new int[n14.size()];
1467 }
1468 j = 0;
1469 for (Atom a14 : n14) {
1470 mask14[i][j++] = a14.getIndex() - 1;
1471 }
1472 }
1473 if (gradient) {
1474 grad.reset(threadID, lb, ub);
1475 }
1476 if (lambdaTerm) {
1477 lambdaGrad.reset(threadID, lb, ub);
1478 }
1479 }
1480
1481 @Override
1482 public IntegerSchedule schedule() {
1483 return IntegerSchedule.fixed();
1484 }
1485
1486 @Override
1487 public void finish() {
1488 time += System.nanoTime();
1489 }
1490
1491 @Override
1492 public void start() {
1493 threadID = getThreadIndex();
1494 time = -System.nanoTime();
1495 }
1496 }
1497
1498 private class ExpandLoop extends IntegerForLoop {
1499
1500 private final double[] in = new double[3];
1501 private final double[] out = new double[3];
1502 private long time;
1503
1504 @Override
1505 public void finish() {
1506 time += System.nanoTime();
1507 }
1508
1509 @Override
1510 public void run(int lb, int ub) {
1511
1512
1513
1514
1515 for (int i = lb; i <= ub; i++) {
1516 int i3 = i * 3;
1517 int iX = i3 + XX;
1518 int iY = i3 + YY;
1519 int iZ = i3 + ZZ;
1520 double x = coordinates[iX];
1521 double y = coordinates[iY];
1522 double z = coordinates[iZ];
1523 int redIndex = reductionIndex[i];
1524 if (redIndex >= 0) {
1525 int r3 = redIndex * 3;
1526 double rx = coordinates[r3++];
1527 double ry = coordinates[r3++];
1528 double rz = coordinates[r3];
1529 double a = reductionValue[i];
1530 reducedXYZ[iX] = a * (x - rx) + rx;
1531 reducedXYZ[iY] = a * (y - ry) + ry;
1532 reducedXYZ[iZ] = a * (z - rz) + rz;
1533 in[0] = reducedXYZ[iX];
1534 in[1] = reducedXYZ[iY];
1535 in[2] = reducedXYZ[iZ];
1536 atoms[i].setRedXYZ(in);
1537 } else {
1538 reducedXYZ[iX] = x;
1539 reducedXYZ[iY] = y;
1540 reducedXYZ[iZ] = z;
1541 }
1542 }
1543
1544 List<SymOp> symOps = crystal.spaceGroup.symOps;
1545
1546 if (symOps.size() != nSymm) {
1547 String message = format(" Programming Error: nSymm %d != symOps.size %d", nSymm, symOps.size());
1548 logger.log(Level.WARNING, message);
1549 logger.log(Level.WARNING, " Replicates\n{0}", crystal.toString());
1550 logger.log(Level.WARNING, " Unit Cell\n{0}", crystal.getUnitCell().toString());
1551 }
1552
1553 double sp2 = crystal.getSpecialPositionCutoff();
1554 sp2 *= sp2;
1555 for (int iSymOp = 1; iSymOp < nSymm; iSymOp++) {
1556 SymOp symOp = symOps.get(iSymOp);
1557 double[] xyz = reduced[iSymOp];
1558 for (int i = lb; i <= ub; i++) {
1559 int i3 = i * 3;
1560 int iX = i3 + XX;
1561 int iY = i3 + YY;
1562 int iZ = i3 + ZZ;
1563 in[0] = reducedXYZ[iX];
1564 in[1] = reducedXYZ[iY];
1565 in[2] = reducedXYZ[iZ];
1566 crystal.applySymOp(in, out, symOp);
1567 xyz[iX] = out[0];
1568 xyz[iY] = out[1];
1569 xyz[iZ] = out[2];
1570
1571
1572 double dx = in[0] - out[0];
1573 double dy = in[1] - out[1];
1574 double dz = in[2] - out[2];
1575 double r2 = dx * dx + dy * dy + dz * dz;
1576 if (r2 < sp2 && logger.isLoggable(Level.FINEST)) {
1577 logger.log(Level.FINEST, " Atom may be at a special position: {0}", atoms[i].toString());
1578 }
1579 }
1580 }
1581 }
1582
1583 @Override
1584 public IntegerSchedule schedule() {
1585 return IntegerSchedule.fixed();
1586 }
1587
1588 @Override
1589 public void start() {
1590 time = -System.nanoTime();
1591 }
1592
1593 }
1594
1595
1596
1597
1598
1599
1600
1601
1602 private class VanDerWaalsLoop extends IntegerForLoop {
1603 protected long time;
1604 private final double[] dx_local;
1605 private final double[][] transOp;
1606 private int count;
1607 private double energy;
1608 private int threadID;
1609 private double dEdL;
1610 private double d2EdL2;
1611 private double[] mask;
1612 private boolean[] vdw14;
1613 private LambdaFactors lambdaFactorsLocal;
1614
1615 VanDerWaalsLoop() {
1616 super();
1617 dx_local = new double[3];
1618 transOp = new double[3][3];
1619 }
1620
1621 @Override
1622 public void finish() {
1623
1624 sharedEnergy.addAndGet(energy);
1625 sharedInteractions.addAndGet(count);
1626 if (lambdaTerm) {
1627 shareddEdL.addAndGet(dEdL);
1628 sharedd2EdL2.addAndGet(d2EdL2);
1629 }
1630 time += System.nanoTime();
1631 }
1632
1633 public int getCount() {
1634 return count;
1635 }
1636
1637 @Override
1638 public void run(int lb, int ub) {
1639 double e = 0.0;
1640 double[] xyzS = reduced[0];
1641
1642 int[][] list = neighborLists[0];
1643 double[] esvVdwPrefactori = new double[3];
1644 double[] esvVdwPrefactork = new double[3];
1645 for (int i = lb; i <= ub; i++) {
1646 if (!use[i]) {
1647 continue;
1648 }
1649
1650 final boolean esvi = esvTerm && esvSystem.isTitratingHydrogen(i);
1651 if (esvTerm) {
1652 esvSystem.getVdwPrefactor(i, esvVdwPrefactori);
1653 }
1654 int i3 = i * 3;
1655
1656 final double xi = reducedXYZ[i3++];
1657 final double yi = reducedXYZ[i3++];
1658 final double zi = reducedXYZ[i3];
1659
1660 final int redi = reductionIndex[i];
1661
1662 final double redv = reductionValue[i];
1663 final double rediv = 1.0 - redv;
1664 final int classI = atomClass[i];
1665
1666 final int moleculei = molecule[i];
1667
1668 boolean iNN = neuralNetwork[i];
1669
1670 double gxi = 0.0;
1671 double gyi = 0.0;
1672 double gzi = 0.0;
1673
1674 double gxredi = 0.0;
1675 double gyredi = 0.0;
1676 double gzredi = 0.0;
1677
1678 double lxi = 0.0;
1679 double lyi = 0.0;
1680 double lzi = 0.0;
1681
1682 double lxredi = 0.0;
1683 double lyredi = 0.0;
1684 double lzredi = 0.0;
1685
1686
1687 applyMask(i, vdw14, mask);
1688
1689 boolean[] softCorei = softCore[HARD];
1690 if (isSoft[i]) {
1691 softCorei = softCore[SOFT];
1692 }
1693
1694 final int[] neighbors = list[i];
1695 for (final int k : neighbors) {
1696
1697
1698 if (!use[k] || (iNN && neuralNetwork[k])) {
1699 continue;
1700 }
1701
1702 final boolean esvk = esvTerm && esvSystem.isTitratingHydrogen(k);
1703 if (esvTerm) {
1704 esvSystem.getVdwPrefactor(k, esvVdwPrefactork);
1705 }
1706 int k3 = k * 3;
1707
1708 final double xk = xyzS[k3++];
1709 final double yk = xyzS[k3++];
1710 final double zk = xyzS[k3];
1711
1712 dx_local[0] = xi - xk;
1713 dx_local[1] = yi - yk;
1714 dx_local[2] = zi - zk;
1715
1716 final double r2 = crystal.image(dx_local);
1717 int classK = atomClass[k];
1718 double irv = vdwForm.getCombinedInverseRmin(classI, classK);
1719 if (vdw14[k]) {
1720
1721 irv = vdwForm.getCombinedInverseRmin14(classI, classK);
1722 }
1723 if (r2 <= nonbondedCutoff.off2 && mask[k] > 0 && irv > 0) {
1724
1725 final double r = sqrt(r2);
1726
1727 boolean sameMolecule = (moleculei == molecule[k]);
1728 boolean soft = softCorei[k];
1729
1730
1731 if (isSoft[i] && isSoft[k]) {
1732 if (intermolecularSoftcore && !sameMolecule) {
1733 soft = true;
1734 } else if (intramolecularSoftcore && sameMolecule) {
1735 soft = true;
1736 }
1737 }
1738
1739 final double sc1, dsc1dL, d2sc1dL2;
1740 final double sc2, dsc2dL, d2sc2dL2;
1741 if (soft) {
1742
1743
1744
1745
1746 sc1 = lambdaFactorsLocal.sc1;
1747 dsc1dL = lambdaFactorsLocal.dsc1dL;
1748 d2sc1dL2 = lambdaFactorsLocal.d2sc1dL2;
1749 sc2 = lambdaFactorsLocal.sc2;
1750 dsc2dL = lambdaFactorsLocal.dsc2dL;
1751 d2sc2dL2 = lambdaFactorsLocal.d2sc2dL2;
1752 } else {
1753 sc1 = 0.0;
1754 dsc1dL = 0.0;
1755 d2sc1dL2 = 0.0;
1756 sc2 = 1.0;
1757 dsc2dL = 0.0;
1758 d2sc2dL2 = 0.0;
1759 }
1760 final double alpha = sc1;
1761 final double lambda5 = sc2;
1762
1763
1764
1765
1766
1767
1768 double ev = mask[k] * vdwForm.getCombinedEps(classI, classK);
1769 if (vdw14[k]) {
1770 ev = mask[k] * vdwForm.getCombinedEps14(classI, classK);
1771 }
1772 final double eps_lambda = ev * lambda5;
1773 final double rho = r * irv;
1774 final double rhoDisp1 = vdwForm.rhoDisp1(rho);
1775 final double rhoDisp = rhoDisp1 * rho;
1776 final double rhoDelta1 = vdwForm.rhoDelta1(rho + vdwForm.delta);
1777 final double rhoDelta = rhoDelta1 * (rho + vdwForm.delta);
1778 final double alphaRhoDelta = alpha + rhoDelta;
1779 final double alphaRhoDispGamma = alpha + rhoDisp + vdwForm.gamma;
1780 final double t1d = 1.0 / alphaRhoDelta;
1781 final double t2d = 1.0 / alphaRhoDispGamma;
1782 final double t1 = vdwForm.t1n * t1d;
1783 final double t2a = vdwForm.gamma1 * t2d;
1784 final double t2 = t2a - 2.0;
1785 double eik = eps_lambda * t1 * t2;
1786
1787
1788
1789
1790 double taper = 1.0;
1791 double dtaper = 0.0;
1792 if (r2 > nonbondedCutoff.cut2) {
1793 final double r3 = r2 * r;
1794 final double r4 = r2 * r2;
1795 final double r5 = r2 * r3;
1796 taper = multiplicativeSwitch.taper(r, r2, r3, r4, r5);
1797 dtaper = multiplicativeSwitch.dtaper(r, r2, r3, r4);
1798 }
1799 double esvik = 1.0;
1800 if (esvi || esvk) {
1801 esvik = esvVdwPrefactori[0] * esvVdwPrefactork[0];
1802 }
1803 e += eik * taper * esvik;
1804
1805 count++;
1806 if (!gradient && !soft) {
1807 continue;
1808 }
1809 final int redk = reductionIndex[k];
1810 final double red = reductionValue[k];
1811 final double redkv = 1.0 - red;
1812 final double dt1d_dr = vdwForm.repDispPower * rhoDelta1 * irv;
1813 final double dt2d_dr = vdwForm.dispersivePower * rhoDisp1 * irv;
1814 final double dt1_dr = t1 * dt1d_dr * t1d;
1815 final double dt2_dr = t2a * dt2d_dr * t2d;
1816 double dedr = -eps_lambda * (dt1_dr * t2 + t1 * dt2_dr);
1817 final double ir = 1.0 / r;
1818 final double drdx = dx_local[0] * ir;
1819 final double drdy = dx_local[1] * ir;
1820 final double drdz = dx_local[2] * ir;
1821 if (gradient) {
1822 final double dswitch = esvik * (eik * dtaper + dedr * taper);
1823 final double dedx = dswitch * drdx;
1824 final double dedy = dswitch * drdy;
1825 final double dedz = dswitch * drdz;
1826 gxi += dedx * redv;
1827 gyi += dedy * redv;
1828 gzi += dedz * redv;
1829 gxredi += dedx * rediv;
1830 gyredi += dedy * rediv;
1831 gzredi += dedz * rediv;
1832 grad.sub(threadID, k, red * dedx, red * dedy, red * dedz);
1833 grad.sub(threadID, redk, redkv * dedx, redkv * dedy, redkv * dedz);
1834
1835 if (esvi) {
1836 esvSystem.addVdwDeriv(i, eik * taper, esvVdwPrefactori, esvVdwPrefactork[0]);
1837 }
1838 if (esvk) {
1839 esvSystem.addVdwDeriv(k, eik * taper, esvVdwPrefactork, esvVdwPrefactori[0]);
1840 }
1841 }
1842 if (gradient && soft) {
1843 final double dt1 = -t1 * t1d * dsc1dL;
1844 final double dt2 = -t2a * t2d * dsc1dL;
1845 final double f1 = dsc2dL * t1 * t2;
1846 final double f2 = sc2 * dt1 * t2;
1847 final double f3 = sc2 * t1 * dt2;
1848 final double dedl = ev * (f1 + f2 + f3);
1849 dEdL += dedl * taper * esvik;
1850 final double t1d2 = -dsc1dL * t1d * t1d;
1851 final double t2d2 = -dsc1dL * t2d * t2d;
1852 final double d2t1 = -dt1 * t1d * dsc1dL - t1 * t1d * d2sc1dL2 - t1 * t1d2 * dsc1dL;
1853 final double d2t2 =
1854 -dt2 * t2d * dsc1dL - t2a * t2d * d2sc1dL2 - t2a * t2d2 * dsc1dL;
1855 final double df1 = d2sc2dL2 * t1 * t2 + dsc2dL * dt1 * t2 + dsc2dL * t1 * dt2;
1856 final double df2 = dsc2dL * dt1 * t2 + sc2 * d2t1 * t2 + sc2 * dt1 * dt2;
1857 final double df3 = dsc2dL * t1 * dt2 + sc2 * dt1 * dt2 + sc2 * t1 * d2t2;
1858 final double de2dl2 = ev * (df1 + df2 + df3);
1859 d2EdL2 += de2dl2 * taper * esvik;
1860 final double t11 = -dsc2dL * t2 * dt1_dr;
1861 final double t21 = -dsc2dL * t1 * dt2_dr;
1862 final double t13 = 2.0 * sc2 * t2 * dt1_dr * dsc1dL * t1d;
1863 final double t23 = 2.0 * sc2 * t1 * dt2_dr * dsc1dL * t2d;
1864 final double t12 = -sc2 * dt2 * dt1_dr;
1865 final double t22 = -sc2 * dt1 * dt2_dr;
1866 final double dedldr = ev * (t11 + t12 + t13 + t21 + t22 + t23);
1867 final double dswitch = esvik * (dedl * dtaper + dedldr * taper);
1868 final double dedldx = dswitch * drdx;
1869 final double dedldy = dswitch * drdy;
1870 final double dedldz = dswitch * drdz;
1871 lxi += dedldx * redv;
1872 lyi += dedldy * redv;
1873 lzi += dedldz * redv;
1874 lxredi += dedldx * rediv;
1875 lyredi += dedldy * rediv;
1876 lzredi += dedldz * rediv;
1877 if (lambdaTerm) {
1878 lambdaGrad.sub(threadID, k, red * dedldx, red * dedldy, red * dedldz);
1879 lambdaGrad.sub(threadID, redk, redkv * dedldx, redkv * dedldy, redkv * dedldz);
1880 }
1881 }
1882 }
1883 }
1884 if (gradient) {
1885 grad.add(threadID, i, gxi, gyi, gzi);
1886 grad.add(threadID, redi, gxredi, gyredi, gzredi);
1887 if (lambdaTerm) {
1888 lambdaGrad.add(threadID, i, lxi, lyi, lzi);
1889 lambdaGrad.add(threadID, redi, lxredi, lyredi, lzredi);
1890 }
1891 }
1892 removeMask(i, vdw14, mask);
1893 }
1894 energy += e;
1895 List<SymOp> symOps = crystal.spaceGroup.symOps;
1896 for (int iSymOp = 1; iSymOp < nSymm; iSymOp++) {
1897 e = 0.0;
1898 SymOp symOp = symOps.get(iSymOp);
1899
1900 crystal.getTransformationOperator(symOp, transOp);
1901 xyzS = reduced[iSymOp];
1902 list = neighborLists[iSymOp];
1903
1904 for (int i = lb; i <= ub; i++) {
1905 int i3 = i * 3;
1906 if (!use[i]) {
1907 continue;
1908 }
1909 final boolean esvi = esvTerm && esvSystem.isTitratingHydrogen(i);
1910 if (esvTerm) {
1911 esvSystem.getVdwPrefactor(i, esvVdwPrefactori);
1912 }
1913 final double xi = reducedXYZ[i3++];
1914 final double yi = reducedXYZ[i3++];
1915 final double zi = reducedXYZ[i3];
1916 final int redi = reductionIndex[i];
1917 final double redv = reductionValue[i];
1918 final double rediv = 1.0 - redv;
1919 final int classI = atomClass[i];
1920 double gxi = 0.0;
1921 double gyi = 0.0;
1922 double gzi = 0.0;
1923 double gxredi = 0.0;
1924 double gyredi = 0.0;
1925 double gzredi = 0.0;
1926 double lxi = 0.0;
1927 double lyi = 0.0;
1928 double lzi = 0.0;
1929 double lxredi = 0.0;
1930 double lyredi = 0.0;
1931 double lzredi = 0.0;
1932
1933 boolean[] softCorei = softCore[HARD];
1934 if (isSoft[i]) {
1935 softCorei = softCore[SOFT];
1936 }
1937
1938 final int[] neighbors = list[i];
1939 for (final int k : neighbors) {
1940 if (!use[k]) {
1941 continue;
1942 }
1943 final boolean esvk = esvTerm && esvSystem.isTitratingHydrogen(k);
1944 if (esvTerm) {
1945 esvSystem.getVdwPrefactor(k, esvVdwPrefactork);
1946 }
1947
1948 final double sc1, dsc1dL, d2sc1dL2;
1949 final double sc2, dsc2dL, d2sc2dL2;
1950 int k3 = k * 3;
1951 final double xk = xyzS[k3++];
1952 final double yk = xyzS[k3++];
1953 final double zk = xyzS[k3];
1954 dx_local[0] = xi - xk;
1955 dx_local[1] = yi - yk;
1956 dx_local[2] = zi - zk;
1957 final double r2 = crystal.image(dx_local);
1958 int classK = atomClass[k];
1959 final double irv = vdwForm.getCombinedInverseRmin(classI, classK);
1960 if (r2 <= nonbondedCutoff.off2 && irv > 0) {
1961 final double selfScale = (i == k) ? 0.5 : 1.0;
1962 final double r = sqrt(r2);
1963 boolean soft = isSoft[i] || softCorei[k];
1964 if (soft) {
1965 sc1 = lambdaFactorsLocal.sc1;
1966 dsc1dL = lambdaFactorsLocal.dsc1dL;
1967 d2sc1dL2 = lambdaFactorsLocal.d2sc1dL2;
1968 sc2 = lambdaFactorsLocal.sc2;
1969 dsc2dL = lambdaFactorsLocal.dsc2dL;
1970 d2sc2dL2 = lambdaFactorsLocal.d2sc2dL2;
1971 } else {
1972 sc1 = 0.0;
1973 dsc1dL = 0.0;
1974 d2sc1dL2 = 0.0;
1975 sc2 = 1.0;
1976 dsc2dL = 0.0;
1977 d2sc2dL2 = 0.0;
1978 }
1979 final double alpha = sc1;
1980 final double lambdaN = sc2;
1981 final double ev = vdwForm.getCombinedEps(classI, classK);
1982 final double eps_lambda = ev * lambdaN;
1983 final double rho = r * irv;
1984 final double rhoDisp1 = vdwForm.rhoDisp1(rho);
1985 final double rhoDisp = rhoDisp1 * rho;
1986 final double rhoDelta1 = vdwForm.rhoDelta1(rho + vdwForm.delta);
1987 final double rhoDelta = rhoDelta1 * (rho + vdwForm.delta);
1988 final double alphaRhoDelta = alpha + rhoDelta;
1989 final double alphaRhoDispGamma = alpha + rhoDisp + vdwForm.gamma;
1990 final double t1d = 1.0 / alphaRhoDelta;
1991 final double t2d = 1.0 / alphaRhoDispGamma;
1992 final double t1 = vdwForm.t1n * t1d;
1993 final double t2a = vdwForm.gamma1 * t2d;
1994 final double t2 = t2a - 2.0;
1995 double eik = eps_lambda * t1 * t2;
1996
1997
1998 double taper = 1.0;
1999 double dtaper = 0.0;
2000 if (r2 > nonbondedCutoff.cut2) {
2001 final double r3 = r2 * r;
2002 final double r4 = r2 * r2;
2003 final double r5 = r2 * r3;
2004 taper = multiplicativeSwitch.taper(r, r2, r3, r4, r5);
2005 dtaper = multiplicativeSwitch.dtaper(r, r2, r3, r4);
2006 }
2007
2008 double esvik = 1.0;
2009 if (esvi || esvk) {
2010 esvik = esvVdwPrefactori[0] * esvVdwPrefactork[0];
2011 }
2012 e += selfScale * eik * taper * esvik;
2013 count++;
2014 if (!gradient && !soft) {
2015 continue;
2016 }
2017 final int redk = reductionIndex[k];
2018 final double red = reductionValue[k];
2019 final double redkv = 1.0 - red;
2020 final double dt1d_dr = vdwForm.repDispPower * rhoDelta1 * irv;
2021 final double dt2d_dr = vdwForm.dispersivePower * rhoDisp1 * irv;
2022 final double dt1_dr = t1 * dt1d_dr * t1d;
2023 final double dt2_dr = t2a * dt2d_dr * t2d;
2024 double dedr = -eps_lambda * (dt1_dr * t2 + t1 * dt2_dr);
2025
2026 final double ir = 1.0 / r;
2027 double drdx = dx_local[0] * ir;
2028 double drdy = dx_local[1] * ir;
2029 double drdz = dx_local[2] * ir;
2030 dedr = selfScale * esvik * (eik * dtaper + dedr * taper);
2031 if (gradient) {
2032 double dedx = dedr * drdx;
2033 double dedy = dedr * drdy;
2034 double dedz = dedr * drdz;
2035 gxi += dedx * redv;
2036 gyi += dedy * redv;
2037 gzi += dedz * redv;
2038 gxredi += dedx * rediv;
2039 gyredi += dedy * rediv;
2040 gzredi += dedz * rediv;
2041
2042
2043 final double dedxk = dedx * transOp[0][0] + dedy * transOp[1][0] + dedz * transOp[2][0];
2044 final double dedyk = dedx * transOp[0][1] + dedy * transOp[1][1] + dedz * transOp[2][1];
2045 final double dedzk = dedx * transOp[0][2] + dedy * transOp[1][2] + dedz * transOp[2][2];
2046 grad.sub(threadID, k, red * dedxk, red * dedyk, red * dedzk);
2047 grad.sub(threadID, redk, redkv * dedxk, redkv * dedyk, redkv * dedzk);
2048
2049
2050 if (esvi) {
2051 esvSystem.addVdwDeriv(i, selfScale * eik * taper, esvVdwPrefactori,
2052 esvVdwPrefactork[0]);
2053 }
2054 if (esvk) {
2055 esvSystem.addVdwDeriv(k, selfScale * eik * taper, esvVdwPrefactork,
2056 esvVdwPrefactori[0]);
2057 }
2058 }
2059 if (gradient && lambdaTerm && soft) {
2060 double dt1 = -t1 * t1d * dsc1dL;
2061 double dt2 = -t2a * t2d * dsc1dL;
2062 double f1 = dsc2dL * t1 * t2;
2063 double f2 = sc2 * dt1 * t2;
2064 double f3 = sc2 * t1 * dt2;
2065 final double dedl = ev * (f1 + f2 + f3);
2066 dEdL += selfScale * dedl * taper * esvik;
2067 double t1d2 = -dsc1dL * t1d * t1d;
2068 double t2d2 = -dsc1dL * t2d * t2d;
2069 double d2t1 = -dt1 * t1d * dsc1dL - t1 * t1d * d2sc1dL2 - t1 * t1d2 * dsc1dL;
2070 double d2t2 = -dt2 * t2d * dsc1dL - t2a * t2d * d2sc1dL2 - t2a * t2d2 * dsc1dL;
2071 double df1 = d2sc2dL2 * t1 * t2 + dsc2dL * dt1 * t2 + dsc2dL * t1 * dt2;
2072 double df2 = dsc2dL * dt1 * t2 + sc2 * d2t1 * t2 + sc2 * dt1 * dt2;
2073 double df3 = dsc2dL * t1 * dt2 + sc2 * dt1 * dt2 + sc2 * t1 * d2t2;
2074 double de2dl2 = ev * (df1 + df2 + df3);
2075 d2EdL2 += selfScale * de2dl2 * taper * esvik;
2076 double t11 = -dsc2dL * t2 * dt1_dr;
2077 double t12 = -sc2 * dt2 * dt1_dr;
2078 double t13 = 2.0 * sc2 * t2 * dt1_dr * dsc1dL * t1d;
2079 double t21 = -dsc2dL * t1 * dt2_dr;
2080 double t22 = -sc2 * dt1 * dt2_dr;
2081 double t23 = 2.0 * sc2 * t1 * dt2_dr * dsc1dL * t2d;
2082 double dedldr = ev * (t11 + t12 + t13 + t21 + t22 + t23);
2083 dedldr = esvik * (dedl * dtaper + dedldr * taper);
2084 double dedldx = selfScale * dedldr * drdx;
2085 double dedldy = selfScale * dedldr * drdy;
2086 double dedldz = selfScale * dedldr * drdz;
2087 lxi += dedldx * redv;
2088 lyi += dedldy * redv;
2089 lzi += dedldz * redv;
2090 lxredi += dedldx * rediv;
2091 lyredi += dedldy * rediv;
2092 lzredi += dedldz * rediv;
2093
2094
2095 final double dedldxk =
2096 dedldx * transOp[0][0] + dedldy * transOp[1][0] + dedldz * transOp[2][0];
2097 final double dedldyk =
2098 dedldx * transOp[0][1] + dedldy * transOp[1][1] + dedldz * transOp[2][1];
2099 final double dedldzk =
2100 dedldx * transOp[0][2] + dedldy * transOp[1][2] + dedldz * transOp[2][2];
2101 lambdaGrad.sub(threadID, k, red * dedldxk, red * dedldyk, red * dedldzk);
2102 lambdaGrad.sub(threadID, redk, redkv * dedldxk, redkv * dedldyk, redkv * dedldzk);
2103 }
2104 }
2105 }
2106 if (gradient) {
2107 grad.add(threadID, i, gxi, gyi, gzi);
2108 grad.add(threadID, redi, gxredi, gyredi, gzredi);
2109 if (lambdaTerm) {
2110 lambdaGrad.add(threadID, i, lxi, lyi, lzi);
2111 lambdaGrad.add(threadID, redi, lxredi, lyredi, lzredi);
2112 }
2113 }
2114 }
2115 energy += e;
2116 }
2117 }
2118
2119 @Override
2120 public IntegerSchedule schedule() {
2121 return pairwiseSchedule;
2122 }
2123
2124 @Override
2125 public void start() {
2126 threadID = getThreadIndex();
2127 time = -System.nanoTime();
2128 energy = 0.0;
2129 count = 0;
2130 if (lambdaTerm) {
2131 dEdL = 0.0;
2132 d2EdL2 = 0.0;
2133 }
2134 lambdaFactorsLocal = lambdaFactors[threadID];
2135 if (lambdaFactorsLocal == null) {
2136 System.exit(1);
2137 }
2138
2139 if (mask == null || mask.length < nAtoms) {
2140 mask = new double[nAtoms];
2141 fill(mask, 1.0);
2142 vdw14 = new boolean[nAtoms];
2143 fill(vdw14, false);
2144 }
2145 }
2146
2147 }
2148
2149
2150
2151
2152 private class ReductionLoop extends IntegerForLoop {
2153
2154 protected long time;
2155 int threadID;
2156
2157 @Override
2158 public void finish() {
2159 time += System.nanoTime();
2160 }
2161
2162 @Override
2163 public void run(int lb, int ub) {
2164 if (gradient) {
2165 grad.reduce(lb, ub);
2166 for (int i = lb; i <= ub; i++) {
2167 Atom ai = atoms[i];
2168 ai.addToXYZGradient(grad.getX(i), grad.getY(i), grad.getZ(i));
2169 }
2170 }
2171 if (lambdaTerm) {
2172 lambdaGrad.reduce(lb, ub);
2173 }
2174 }
2175
2176 @Override
2177 public void start() {
2178 threadID = getThreadIndex();
2179 time = -System.nanoTime();
2180 }
2181
2182 }
2183
2184
2185
2186
2187 private class NeighborListBarrier extends BarrierAction {
2188
2189 @Override
2190 public void run() {
2191 neighborListTotalTime = -System.nanoTime();
2192 neighborList.buildList(reduced, neighborLists, null, forceNeighborListRebuild, false);
2193 neighborListTotalTime += System.nanoTime();
2194 }
2195 }
2196 }
2197 }