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.algorithms.dynamics;
39
40 import ffx.crystal.Crystal;
41 import ffx.crystal.CrystalPotential;
42 import ffx.crystal.SpaceGroup;
43 import ffx.numerics.Potential;
44 import ffx.numerics.math.RunningStatistics;
45 import ffx.potential.MolecularAssembly;
46 import ffx.potential.bonded.Atom;
47 import ffx.potential.parsers.XYZFilter;
48 import org.apache.commons.io.FilenameUtils;
49
50 import java.io.File;
51 import java.util.ArrayList;
52 import java.util.List;
53 import java.util.logging.Level;
54 import java.util.logging.Logger;
55
56 import static ffx.crystal.LatticeSystem.check;
57 import static ffx.numerics.math.ScalarMath.mirrorDegrees;
58 import static ffx.utilities.Constants.*;
59 import static java.lang.String.format;
60 import static org.apache.commons.math3.util.FastMath.*;
61
62
63
64
65
66
67
68
69
70
71 public class Barostat implements CrystalPotential {
72
73 private static final Logger logger = Logger.getLogger(Barostat.class.getName());
74
75
76
77
78 private final MolecularAssembly molecularAssembly;
79
80
81
82 private Crystal crystal;
83
84
85
86 private Crystal unitCell;
87
88
89
90 private final double mass;
91
92
93
94 private final CrystalPotential potential;
95
96
97
98 private final double[] x;
99
100
101
102 private final int nSymm;
103
104
105
106 private final SpaceGroup spaceGroup;
107
108
109
110 private final int nMolecules;
111
112
113
114 private double kT;
115
116
117
118 private double pressure = 1.0;
119
120
121
122 private boolean isotropic = false;
123
124
125
126 private boolean active = true;
127
128
129
130 private double maxAngleMove = 0.5;
131
132
133
134 private double maxVolumeMove = 1.0;
135
136
137
138 private double minDensity = 0.75;
139
140
141
142 private double maxDensity = 1.60;
143
144
145
146 private int meanBarostatInterval = 1;
147
148
149
150 private int barostatCount = 0;
151
152
153
154 private final RunningStatistics unitCellMoves = new RunningStatistics();
155
156
157
158 private final RunningStatistics sideMoves = new RunningStatistics();
159
160
161
162 private final RunningStatistics angleMoves = new RunningStatistics();
163
164
165
166 private STATE state = STATE.BOTH;
167
168
169
170 private MoveType moveType = MoveType.SIDE;
171
172
173
174 private boolean moveAccepted = false;
175
176
177
178 private double currentDensity = 0;
179
180
181
182 private double a = 0;
183
184
185
186 private double b = 0;
187
188
189
190 private double c = 0;
191
192
193
194 private double alpha = 0;
195
196
197
198 private double beta = 0;
199
200
201
202 private double gamma = 0;
203
204
205
206 private final RunningStatistics aStats = new RunningStatistics();
207
208
209
210 private final RunningStatistics bStats = new RunningStatistics();
211
212
213
214 private final RunningStatistics cStats = new RunningStatistics();
215
216
217
218 private final RunningStatistics alphaStats = new RunningStatistics();
219
220
221
222 private final RunningStatistics betaStats = new RunningStatistics();
223
224
225
226 private final RunningStatistics gammaStats = new RunningStatistics();
227
228
229
230 private final RunningStatistics densityStats = new RunningStatistics();
231
232
233
234 private int printFrequency = 1000;
235
236
237
238
239
240
241
242 public Barostat(MolecularAssembly molecularAssembly, CrystalPotential potential) {
243 this(molecularAssembly, potential, 298.15);
244 }
245
246
247
248
249
250
251
252
253 public Barostat(MolecularAssembly molecularAssembly, CrystalPotential potential,
254 double temperature) {
255
256 this.molecularAssembly = molecularAssembly;
257 this.potential = potential;
258 this.kT = temperature * R;
259
260 crystal = potential.getCrystal();
261 unitCell = crystal.getUnitCell();
262 spaceGroup = unitCell.spaceGroup;
263
264 Atom[] atoms = molecularAssembly.getAtomArray();
265
266 int nAtoms = atoms.length;
267 nSymm = spaceGroup.getNumberOfSymOps();
268 mass = molecularAssembly.getMass();
269 x = new double[3 * nAtoms];
270 nMolecules = molecularAssembly.fractionalCount();
271 }
272
273
274
275
276
277
278 public double density() {
279 return (mass * nSymm / AVOGADRO) * (1.0e24 / unitCell.volume);
280 }
281
282
283
284
285 @Override
286 public boolean destroy() {
287
288 return potential.destroy();
289 }
290
291
292
293
294 @Override
295 public double energy(double[] x) {
296
297 return potential.energy(x);
298 }
299
300
301
302
303 @Override
304 public double energyAndGradient(double[] x, double[] g) {
305
306
307 double energy = potential.energyAndGradient(x, g);
308
309
310 if (active && state != STATE.FAST) {
311 if (random() < (1.0 / meanBarostatInterval)) {
312
313
314 moveAccepted = false;
315
316 applyBarostat(energy);
317
318
319 collectStats();
320
321
322
323 if (moveAccepted) {
324 energy = potential.energyAndGradient(x, g);
325 }
326 }
327 }
328 return energy;
329 }
330
331
332
333
334
335
336
337 public boolean isIsotropic() {
338 return isotropic;
339 }
340
341
342
343
344
345
346
347 public void setIsotropic(boolean isotropic) {
348 this.isotropic = isotropic;
349 }
350
351
352
353
354 @Override
355 public double[] getAcceleration(double[] acceleration) {
356 return potential.getAcceleration(acceleration);
357 }
358
359
360
361
362 @Override
363 public double[] getCoordinates(double[] parameters) {
364 return potential.getCoordinates(parameters);
365 }
366
367
368
369
370 @Override
371 public Crystal getCrystal() {
372 return potential.getCrystal();
373 }
374
375
376
377
378 @Override
379 public void setCrystal(Crystal crystal) {
380 potential.setCrystal(crystal);
381 }
382
383
384
385
386 @Override
387 public STATE getEnergyTermState() {
388 return state;
389 }
390
391
392
393
394 @Override
395 public void setEnergyTermState(STATE state) {
396 this.state = state;
397 potential.setEnergyTermState(state);
398 }
399
400
401
402
403 @Override
404 public double[] getMass() {
405 return potential.getMass();
406 }
407
408
409
410
411
412
413 public int getMeanBarostatInterval() {
414 return meanBarostatInterval;
415 }
416
417
418
419
420
421
422 public void setMeanBarostatInterval(int meanBarostatInterval) {
423 this.meanBarostatInterval = meanBarostatInterval;
424 }
425
426
427
428
429 @Override
430 public int getNumberOfVariables() {
431 return potential.getNumberOfVariables();
432 }
433
434
435
436
437
438
439 public double getPressure() {
440 return pressure;
441 }
442
443
444
445
446
447
448 public void setPressure(double pressure) {
449 this.pressure = pressure;
450 }
451
452
453
454
455 @Override
456 public double[] getPreviousAcceleration(double[] previousAcceleration) {
457 return potential.getPreviousAcceleration(previousAcceleration);
458 }
459
460
461
462
463 @Override
464 public double[] getScaling() {
465 return potential.getScaling();
466 }
467
468
469
470
471 @Override
472 public void setScaling(double[] scaling) {
473 potential.setScaling(scaling);
474 }
475
476
477
478
479 @Override
480 public double getTotalEnergy() {
481 return potential.getTotalEnergy();
482 }
483
484 @Override
485 public List<Potential> getUnderlyingPotentials() {
486 List<Potential> underlying = new ArrayList<>();
487 underlying.add(potential);
488 underlying.addAll(potential.getUnderlyingPotentials());
489 return underlying;
490 }
491
492
493
494
495 @Override
496 public VARIABLE_TYPE[] getVariableTypes() {
497 return potential.getVariableTypes();
498 }
499
500
501
502
503 @Override
504 public double[] getVelocity(double[] velocity) {
505 return potential.getVelocity(velocity);
506 }
507
508 public boolean isActive() {
509 return active;
510 }
511
512
513
514
515
516
517 public void setActive(boolean active) {
518 this.active = active;
519 }
520
521
522
523
524 @Override
525 public void setAcceleration(double[] acceleration) {
526 potential.setAcceleration(acceleration);
527 }
528
529
530
531
532
533
534 public void setDensity(double density) {
535 molecularAssembly.computeFractionalCoordinates();
536 crystal.setDensity(density, mass);
537 potential.setCrystal(crystal);
538 molecularAssembly.moveToFractionalCoordinates();
539 }
540
541
542
543
544
545
546 public void setMaxAngleMove(double maxAngleMove) {
547 this.maxAngleMove = maxAngleMove;
548 }
549
550
551
552
553
554
555 public void setMaxVolumeMove(double maxVolumeMove) {
556 this.maxVolumeMove = maxVolumeMove;
557 }
558
559
560
561
562
563
564 public void setMaxDensity(double maxDensity) {
565 this.maxDensity = maxDensity;
566 }
567
568
569
570
571
572
573 public void setMinDensity(double minDensity) {
574 this.minDensity = minDensity;
575 }
576
577
578
579
580
581
582 public void setBarostatPrintFrequency(int frequency) {
583 this.printFrequency = frequency;
584 }
585
586
587
588
589 @Override
590 public void setPreviousAcceleration(double[] previousAcceleration) {
591 potential.setPreviousAcceleration(previousAcceleration);
592 }
593
594
595
596
597
598
599 public void setTemperature(double temperature) {
600 this.kT = temperature * R;
601 }
602
603
604
605
606 @Override
607 public void setVelocity(double[] velocity) {
608 potential.setVelocity(velocity);
609 }
610
611 private double mcStep(double currentE, double currentV) {
612
613
614 double den = density();
615 if(Double.isNaN(den) || Double.isNaN(a) || Double.isNaN(b) || Double.isNaN(c) || Double.isNaN(alpha) || Double.isNaN(beta) || Double.isNaN(gamma)){
616 logger.warning(format(" Found value of NaN: density: %7.4f a: %7.4f b: %7.4f c: %7.4f alpha: %7.4f beta: %7.4f gamma: %7.4f",
617 den, a, b, c, alpha, beta, gamma));
618 File errorFile = new File(FilenameUtils.removeExtension(molecularAssembly.getFile().getName()) + "_err.xyz");
619 XYZFilter.version(errorFile);
620 XYZFilter writeFilter = new XYZFilter(errorFile, molecularAssembly, molecularAssembly.getForceField(), molecularAssembly.getProperties());
621 writeFilter.writeFile(errorFile, true, null);
622 }
623 if (den < minDensity || den > maxDensity) {
624 if (logger.isLoggable(Level.FINE)) {
625 logger.fine(
626 format(" MC Density %10.6f is outside the range %10.6f - %10.6f.", den, minDensity,
627 maxDensity));
628 }
629
630 crystal.changeUnitCellParameters(a, b, c, alpha, beta, gamma);
631 return currentE;
632 }
633
634
635
636 double minInterfacialRadius = 1.2;
637 double currentMinInterfacialRadius = min(min(unitCell.interfacialRadiusA, unitCell.interfacialRadiusB),
638 unitCell.interfacialRadiusC);
639
640 if (currentMinInterfacialRadius < minInterfacialRadius) {
641 if (logger.isLoggable(Level.FINE)) {
642 logger.fine(format(" MC An interfacial radius (%10.6f,%10.6f,%10.6f) is below the minimum %10.6f",
643 unitCell.interfacialRadiusA, unitCell.interfacialRadiusB,
644 unitCell.interfacialRadiusC, minInterfacialRadius));
645 }
646
647 crystal.changeUnitCellParameters(a, b, c, alpha, beta, gamma);
648 return currentE;
649 }
650
651
652
653 potential.setCrystal(crystal);
654
655
656 molecularAssembly.moveToFractionalCoordinates();
657
658
659 double newV = unitCell.volume / nSymm;
660
661 potential.getCoordinates(x);
662
663
664 double newE = potential.energy(x);
665
666
667 double dPE = newE - currentE;
668
669
670 double dEV = pressure * (newV - currentV) / PRESCON;
671
672
673 double dES = -nMolecules * kT * log(newV / currentV);
674
675
676 double dE = dPE + dEV + dES;
677
678
679 if (dE < 0.0) {
680 if (logger.isLoggable(Level.FINE)) {
681 logger.fine(format(" MC Accept: %12.6f (dPE) + %12.6f (dEV) + %12.6f (dES) = %12.6f with (V=%12.6f, E=%12.6f)",
682 dPE, dEV, dES, dE, newV, newE));
683 }
684 moveAccepted = true;
685 switch (moveType) {
686 case SIDE -> sideMoves.addValue(1.0);
687 case ANGLE -> angleMoves.addValue(1.0);
688 case UNIT -> unitCellMoves.addValue(1.0);
689 }
690 return newE;
691 }
692
693
694 double acceptanceProbability = exp(-dE / kT);
695
696
697
698 double metropolis = random();
699
700
701 if (metropolis > acceptanceProbability) {
702 rejectMove();
703 if (logger.isLoggable(Level.FINE)) {
704 logger.fine(format(" MC Reject: %12.6f (dPE) + %12.6f (dEV) + %12.6f (dES) = %12.6f with (V=%12.6f, E=%12.6f)",
705 dPE, dEV, dES, dE, currentV, currentE));
706 }
707 switch (moveType) {
708 case SIDE -> sideMoves.addValue(0.0);
709 case ANGLE -> angleMoves.addValue(0.0);
710 case UNIT -> unitCellMoves.addValue(0.0);
711 }
712 return currentE;
713 }
714
715
716 if (logger.isLoggable(Level.FINE)) {
717 logger.fine(format(" MC Accept: %12.6f (dPE) + %12.6f (dEV) + %12.6f (dES) = %12.6f with (V=%12.6f, E=%12.6f)",
718 dPE, dEV, dES, dE, newV, newE));
719 }
720
721 moveAccepted = true;
722 switch (moveType) {
723 case SIDE -> sideMoves.addValue(1.0);
724 case ANGLE -> angleMoves.addValue(1.0);
725 case UNIT -> unitCellMoves.addValue(1.0);
726 }
727
728 return newE;
729 }
730
731
732
733
734 private void rejectMove() {
735
736 crystal.changeUnitCellParameters(a, b, c, alpha, beta, gamma);
737
738
739 potential.setCrystal(crystal);
740
741
742 molecularAssembly.moveToFractionalCoordinates();
743 }
744
745
746
747
748
749
750
751 private double mcA(double currentE) {
752 moveType = MoveType.SIDE;
753 double currentAUV = unitCell.volume / nSymm;
754 double dAUVolume = maxVolumeMove * (2.0 * random() - 1.0);
755 double dVdA = unitCell.dVdA / nSymm;
756 double dA = dAUVolume / dVdA;
757 boolean succeed = crystal.changeUnitCellParameters(a + dA, b, c, alpha, beta, gamma);
758 if (succeed) {
759 if (logger.isLoggable(Level.FINE)) {
760 logger.fine(format(" Proposing MC change of the a-axis to (%6.3f) with volume change %6.3f (A^3)", a, dAUVolume));
761 }
762 return mcStep(currentE, currentAUV);
763 }
764 return currentE;
765 }
766
767
768
769
770
771
772
773 private double mcB(double currentE) {
774 moveType = MoveType.SIDE;
775 double currentAUV = unitCell.volume / nSymm;
776 double dAUVolume = maxVolumeMove * (2.0 * random() - 1.0);
777 double dVdB = unitCell.dVdB / nSymm;
778 double dB = dAUVolume / dVdB;
779 boolean succeed = crystal.changeUnitCellParameters(a, b + dB, c, alpha, beta, gamma);
780 if (succeed) {
781 if (logger.isLoggable(Level.FINE)) {
782 logger.fine(format(" Proposing MC change of the b-axis to (%6.3f) with volume change %6.3f (A^3)", b, dAUVolume));
783 }
784 return mcStep(currentE, currentAUV);
785 }
786 return currentE;
787 }
788
789
790
791
792
793
794
795 private double mcC(double currentE) {
796 moveType = MoveType.SIDE;
797 double currentAUV = unitCell.volume / nSymm;
798 double dAUVolume = maxVolumeMove * (2.0 * random() - 1.0);
799 double dVdC = unitCell.dVdC / nSymm;
800 double dC = dAUVolume / dVdC;
801 boolean succeed = crystal.changeUnitCellParameters(a, b, c + dC, alpha, beta, gamma);
802 if (succeed) {
803 if (logger.isLoggable(Level.FINE)) {
804 logger.fine(format(" Proposing MC change to the c-axis to (%6.3f) with volume change %6.3f (A^3)", c, dAUVolume));
805 }
806 return mcStep(currentE, currentAUV);
807 }
808 return currentE;
809 }
810
811
812
813
814
815
816
817 private double mcAB(double currentE) {
818 moveType = MoveType.SIDE;
819 double currentAUV = unitCell.volume / nSymm;
820 double dAUVolume = maxVolumeMove * (2.0 * random() - 1.0);
821 double dVdAB = (unitCell.dVdA + unitCell.dVdB) / nSymm;
822 double dAB = dAUVolume / dVdAB;
823 boolean succeed = crystal.changeUnitCellParametersAndVolume(a + dAB, b + dAB, c, alpha, beta,
824 gamma, currentAUV + dAUVolume);
825 if (succeed) {
826 if (logger.isLoggable(Level.FINE)) {
827 logger.fine(format(" Proposing MC change to the a,b-axes to (%6.3f) with volume change %6.3f (A^3)", a, dAUVolume));
828 }
829 return mcStep(currentE, currentAUV);
830 }
831 return currentE;
832 }
833
834 private double mcABC(double currentE) {
835 moveType = MoveType.SIDE;
836 double currentAUV = unitCell.volume / nSymm;
837 double dAUVolume = maxVolumeMove * (2.0 * random() - 1.0);
838 double dVdABC = (unitCell.dVdA + unitCell.dVdB + unitCell.dVdC) / nSymm;
839 double dABC = dAUVolume / dVdABC;
840 boolean succeed = crystal.changeUnitCellParametersAndVolume(a + dABC, b + dABC, c + dABC, alpha,
841 beta, gamma, currentAUV + dAUVolume);
842 if (succeed) {
843 if (logger.isLoggable(Level.FINE)) {
844 logger.fine(format(" Proposing MC change to the a,b,c-axes to (%6.3f) with volume change %6.3f (A^3)", a, dAUVolume));
845 }
846 return mcStep(currentE, currentAUV);
847 }
848 return currentE;
849 }
850
851
852
853
854
855
856
857 private double mcAlpha(double currentE) {
858 moveType = MoveType.ANGLE;
859 double move = maxAngleMove * (2.0 * random() - 1.0);
860 double currentAUV = unitCell.volume / nSymm;
861 double newAlpha = mirrorDegrees(alpha + move);
862 boolean succeed = crystal.changeUnitCellParametersAndVolume(a, b, c, newAlpha, beta, gamma, currentAUV);
863 if (succeed) {
864 if (logger.isLoggable(Level.FINE)) {
865 logger.fine(format(" Proposing MC change of alpha to %6.3f.", newAlpha));
866 }
867 return mcStep(currentE, currentAUV);
868 }
869 return currentE;
870 }
871
872
873
874
875
876
877
878 private double mcBeta(double currentE) {
879 moveType = MoveType.ANGLE;
880 double move = maxAngleMove * (2.0 * random() - 1.0);
881 double currentAUV = unitCell.volume / nSymm;
882 double newBeta = mirrorDegrees(beta + move);
883 boolean succeed = crystal.changeUnitCellParametersAndVolume(a, b, c, alpha, newBeta, gamma, currentAUV);
884 if (succeed) {
885 if (logger.isLoggable(Level.FINE)) {
886 logger.fine(format(" Proposing MC change of beta to %6.3f.", newBeta));
887 }
888 return mcStep(currentE, currentAUV);
889 }
890 return currentE;
891 }
892
893
894
895
896
897
898
899 private double mcGamma(double currentE) {
900 moveType = MoveType.ANGLE;
901 double move = maxAngleMove * (2.0 * random() - 1.0);
902 double currentAUV = unitCell.volume / nSymm;
903 double newGamma = mirrorDegrees(gamma + move);
904 boolean succeed = crystal.changeUnitCellParametersAndVolume(a, b, c, alpha, beta, newGamma, currentAUV);
905 if (succeed) {
906 if (logger.isLoggable(Level.FINE)) {
907 logger.fine(format(" Proposing MC change of gamma to %6.3f.", newGamma));
908 }
909 return mcStep(currentE, currentAUV);
910 }
911 return currentE;
912 }
913
914
915
916
917
918
919
920 private double mcABG(double currentE) {
921 moveType = MoveType.ANGLE;
922 double move = maxAngleMove * (2.0 * random() - 1.0);
923 double currentAUV = unitCell.volume / nSymm;
924 double newAlpha = mirrorDegrees(alpha + move);
925 double newBeta = mirrorDegrees(beta + move);
926 double newGamma = mirrorDegrees(gamma + move);
927 boolean succeed = crystal.changeUnitCellParametersAndVolume(a, b, c, newAlpha, newBeta, newGamma, currentAUV);
928 if (succeed) {
929 if (logger.isLoggable(Level.FINE)) {
930 logger.fine(format(" Proposing MC change to all angles to %6.3f.", newAlpha));
931 }
932 return mcStep(currentE, currentAUV);
933 }
934 return currentE;
935 }
936
937
938
939
940
941
942
943 private double applyBarostat(double currentE) {
944
945 molecularAssembly.computeFractionalCoordinates();
946
947
948 crystal = potential.getCrystal();
949 unitCell = crystal.getUnitCell();
950 a = unitCell.a;
951 b = unitCell.b;
952 c = unitCell.c;
953 alpha = unitCell.alpha;
954 beta = unitCell.beta;
955 gamma = unitCell.gamma;
956
957 if (isotropic) {
958 currentE = mcABC(currentE);
959 } else {
960 switch (spaceGroup.latticeSystem) {
961 case MONOCLINIC_LATTICE -> {
962
963 int move = (int) floor(random() * 4.0);
964 switch (move) {
965 case 0 -> currentE = mcA(currentE);
966 case 1 -> currentE = mcB(currentE);
967 case 2 -> currentE = mcC(currentE);
968 case 3 -> currentE = mcBeta(currentE);
969 default -> logger.severe(" Barostat programming error.");
970 }
971 }
972 case ORTHORHOMBIC_LATTICE -> {
973
974 int move = (int) floor(random() * 3.0);
975 switch (move) {
976 case 0 -> currentE = mcA(currentE);
977 case 1 -> currentE = mcB(currentE);
978 case 2 -> currentE = mcC(currentE);
979 default -> logger.severe(" Barostat programming error.");
980 }
981 }
982 case TETRAGONAL_LATTICE -> {
983
984 int move = (int) floor(random() * 2.0);
985 switch (move) {
986 case 0 -> currentE = mcAB(currentE);
987 case 1 -> currentE = mcC(currentE);
988 default -> logger.severe(" Barostat programming error.");
989 }
990 }
991 case RHOMBOHEDRAL_LATTICE -> {
992
993 int move = (int) floor(random() * 2.0);
994 switch (move) {
995 case 0 -> currentE = mcABC(currentE);
996 case 1 -> currentE = mcABG(currentE);
997 default -> logger.severe(" Barostat programming error.");
998 }
999 }
1000 case HEXAGONAL_LATTICE -> {
1001
1002 int move = (int) floor(random() * 2.0);
1003 switch (move) {
1004 case 0 -> currentE = mcAB(currentE);
1005 case 1 -> currentE = mcC(currentE);
1006 default -> logger.severe(" Barostat programming error.");
1007 }
1008 }
1009 case CUBIC_LATTICE ->
1010
1011 currentE = mcABC(currentE);
1012 case TRICLINIC_LATTICE -> {
1013 if (check(a, b) && check(b, c) && check(alpha, 90.0) && check(beta, 90.0) && check(gamma, 90.0)) {
1014 currentE = mcABC(currentE);
1015 } else {
1016 int move = (int) floor(random() * 6.0);
1017 switch (move) {
1018 case 0 -> currentE = mcA(currentE);
1019 case 1 -> currentE = mcB(currentE);
1020 case 2 -> currentE = mcC(currentE);
1021 case 3 -> currentE = mcAlpha(currentE);
1022 case 4 -> currentE = mcBeta(currentE);
1023 case 5 -> currentE = mcGamma(currentE);
1024 default -> logger.severe(" Barostat programming error.");
1025 }
1026 }
1027 }
1028 }
1029 }
1030
1031 currentDensity = density();
1032 if (moveAccepted) {
1033 if (logger.isLoggable(Level.FINE)) {
1034 StringBuilder sb = new StringBuilder(" MC Barostat Acceptance:");
1035 if (sideMoves.getCount() > 0) {
1036 sb.append(format(" Side %5.1f%%", sideMoves.getMean() * 100.0));
1037 }
1038 if (angleMoves.getCount() > 0) {
1039 sb.append(format(" Angle %5.1f%%", angleMoves.getMean() * 100.0));
1040 }
1041 if (unitCellMoves.getCount() > 0) {
1042 sb.append(format(" UC %5.1f%%", unitCellMoves.getMean() * 100.0));
1043 }
1044 sb.append(format("\n Density: %5.3f UC: %s", currentDensity, unitCell.toShortString()));
1045 logger.fine(sb.toString());
1046 }
1047 } else {
1048
1049 if (unitCell.a != a || unitCell.b != b || unitCell.c != c || unitCell.alpha != alpha
1050 || unitCell.beta != beta || unitCell.gamma != gamma) {
1051 logger.severe(" Reversion of unit cell parameters did not succeed after failed Barostat MC move.");
1052 }
1053 }
1054
1055 return currentE;
1056 }
1057
1058
1059
1060
1061 private void collectStats() {
1062
1063 barostatCount++;
1064
1065
1066 if(Double.isNaN(currentDensity)||Double.isNaN(a)||Double.isNaN(b)||Double.isNaN(c)||Double.isNaN(alpha)||Double.isNaN(beta)||Double.isNaN(gamma)){
1067 logger.warning(format(" Statistic Value was NaN: Density: %5.3f A: %5.3f B: %5.3f C: %5.3f Alpha: %5.3f Beta: %5.3f Gamma: %5.3f",
1068 currentDensity, a, b, c, alpha, beta, gamma));
1069 }
1070 densityStats.addValue(currentDensity);
1071 aStats.addValue(a);
1072 bStats.addValue(b);
1073 cStats.addValue(c);
1074 alphaStats.addValue(alpha);
1075 betaStats.addValue(beta);
1076 gammaStats.addValue(gamma);
1077 if (barostatCount % printFrequency == 0) {
1078 logger.info(format(" Barostat statistics for the last %d moves:", printFrequency));
1079
1080 logger.info(format(" Density: %5.3f±%5.3f with range %5.3f .. %5.3f (g/cc)", densityStats.getMean(),
1081 densityStats.getStandardDeviation(), densityStats.getMin(), densityStats.getMax()));
1082 densityStats.reset();
1083
1084 logger.info(format(" Lattice a-axis: %5.2f±%3.2f b-axis: %5.2f±%3.2f c-axis: %5.2f±%3.2f",
1085 aStats.getMean(), aStats.getStandardDeviation(), bStats.getMean(), bStats.getStandardDeviation(), cStats.getMean(),
1086 cStats.getStandardDeviation()));
1087 logger.info(format(" alpha: %5.2f±%3.2f beta: %5.2f±%3.2f gamma: %5.2f±%3.2f",
1088 alphaStats.getMean(), alphaStats.getStandardDeviation(), betaStats.getMean(),
1089 betaStats.getStandardDeviation(), gammaStats.getMean(), gammaStats.getStandardDeviation()));
1090 aStats.reset();
1091 bStats.reset();
1092 cStats.reset();
1093 alphaStats.reset();
1094 betaStats.reset();
1095 gammaStats.reset();
1096
1097 if (sideMoves.getCount() > 0) {
1098 logger.info(format(" Axis length moves: %4d (%5.2f%%)", sideMoves.getCount(), sideMoves.getMean() * 100.0));
1099 sideMoves.reset();
1100 }
1101 if (angleMoves.getCount() > 0) {
1102 logger.info(format(" Angle moves: %4d (%5.2f%%)", angleMoves.getCount(), angleMoves.getMean() * 100.0));
1103 angleMoves.reset();
1104 }
1105 if (unitCellMoves.getCount() > 0) {
1106 logger.info(format(" Unit cell moves: %4d (%5.2f%%)", unitCellMoves.getCount(), unitCellMoves.getMean() * 100.0));
1107 unitCellMoves.reset();
1108 }
1109 }
1110 }
1111
1112
1113
1114
1115 private enum MoveType {
1116 SIDE, ANGLE, UNIT
1117 }
1118 }