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.thermodynamics;
39
40 import edu.rit.mp.DoubleBuf;
41 import edu.rit.pj.Comm;
42 import ffx.algorithms.AlgorithmListener;
43 import ffx.algorithms.cli.DynamicsOptions;
44 import ffx.algorithms.cli.LambdaParticleOptions;
45 import ffx.algorithms.dynamics.Barostat;
46 import ffx.algorithms.dynamics.integrators.Stochastic;
47 import ffx.algorithms.optimize.Minimize;
48 import ffx.crystal.Crystal;
49 import ffx.crystal.CrystalPotential;
50 import ffx.numerics.Potential;
51 import ffx.numerics.integrate.DataSet;
52 import ffx.numerics.integrate.DoublesDataSet;
53 import ffx.numerics.integrate.Integrate1DNumeric;
54 import ffx.numerics.integrate.Integrate1DNumeric.IntegrationType;
55 import ffx.potential.MolecularAssembly;
56 import ffx.potential.SystemState;
57 import ffx.potential.Utilities;
58 import ffx.potential.bonded.LambdaInterface;
59 import ffx.potential.parsers.PDBFilter;
60 import ffx.potential.parsers.SystemFilter;
61 import ffx.potential.parsers.XYZFilter;
62 import org.apache.commons.configuration2.CompositeConfiguration;
63 import org.apache.commons.io.FilenameUtils;
64
65 import javax.annotation.Nullable;
66 import java.io.File;
67 import java.io.PrintWriter;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.List;
71 import java.util.Optional;
72 import java.util.logging.Level;
73 import java.util.logging.Logger;
74
75 import static ffx.numerics.integrate.Integrate1DNumeric.IntegrationType.SIMPSONS;
76 import static ffx.utilities.Constants.R;
77 import static java.lang.String.format;
78 import static java.lang.System.arraycopy;
79 import static java.util.Arrays.fill;
80 import static org.apache.commons.math3.util.FastMath.PI;
81 import static org.apache.commons.math3.util.FastMath.abs;
82 import static org.apache.commons.math3.util.FastMath.asin;
83 import static org.apache.commons.math3.util.FastMath.exp;
84 import static org.apache.commons.math3.util.FastMath.floor;
85 import static org.apache.commons.math3.util.FastMath.sin;
86 import static org.apache.commons.math3.util.FastMath.sqrt;
87
88
89
90
91
92
93
94
95
96
97
98 public class OrthogonalSpaceTempering implements CrystalPotential, LambdaInterface {
99
100 private static final Logger logger = Logger.getLogger(OrthogonalSpaceTempering.class.getName());
101
102
103
104 protected final CrystalPotential potential;
105
106
107
108 protected final AlgorithmListener algorithmListener;
109
110
111
112 protected final boolean print = false;
113
114
115
116 protected final int nVariables;
117
118
119
120 private final LambdaInterface lambdaInterface;
121
122
123
124 private final List<Histogram> allHistograms = new ArrayList<>();
125
126
127
128 private final OptimizationParameters optimizationParameters;
129
130
131
132 private final CompositeConfiguration properties;
133
134
135
136 protected MolecularAssembly molecularAssembly;
137
138
139
140
141 protected Potential.STATE state = Potential.STATE.BOTH;
142
143
144
145 protected double forceFieldEnergy;
146
147
148
149 private Histogram histogram;
150
151
152
153 private int histogramIndex;
154
155
156
157 private boolean propagateLambda = true;
158
159
160
161 private final double[] dUdXdL;
162
163
164
165
166 private final double[] tempGradient;
167
168
169
170
171 private double dForceFieldEnergydL;
172
173
174
175 private double gLdEdL = 0.0;
176
177
178
179 private double biasEnergy;
180
181
182
183 private double totalEnergy;
184
185
186
187 private double dUdLambda;
188
189
190
191 private double d2UdL2;
192
193
194
195 private boolean hardWallConstraint = false;
196
197 private final DynamicsOptions dynamicsOptions;
198
199 private final LambdaParticleOptions lambdaParticleOptions;
200
201
202
203
204
205
206
207
208
209
210
211
212
213 public OrthogonalSpaceTempering(LambdaInterface lambdaInterface, CrystalPotential potential,
214 HistogramData histogramData, LambdaData lambdaData, CompositeConfiguration properties,
215 DynamicsOptions dynamicsOptions, LambdaParticleOptions lambdaParticleOptions,
216 AlgorithmListener algorithmListener) {
217 this.lambdaInterface = lambdaInterface;
218 this.potential = potential;
219 this.properties = properties;
220 this.dynamicsOptions = dynamicsOptions;
221 this.lambdaParticleOptions = lambdaParticleOptions;
222 this.algorithmListener = algorithmListener;
223 nVariables = potential.getNumberOfVariables();
224
225 if (potential instanceof Barostat) {
226 logger.severe(" The Barostat must wrap the OST instance.");
227 }
228
229 dUdXdL = new double[nVariables];
230 tempGradient = new double[nVariables];
231
232
233 histogram = new Histogram(properties, histogramData, lambdaData);
234 histogramIndex = 0;
235 allHistograms.add(histogram);
236
237
238 optimizationParameters = new OptimizationParameters(properties);
239 }
240
241
242
243
244
245
246 public void addHistogram(HistogramData histogramData, LambdaData lambdaData) {
247 Histogram newHisto = new Histogram(properties, histogramData, lambdaData);
248 histogramData.asynchronous = this.histogram.hd.asynchronous;
249 allHistograms.add(newHisto);
250 }
251
252
253
254
255 @Override
256 public boolean dEdLZeroAtEnds() {
257 return false;
258 }
259
260
261
262
263 @Override
264 public boolean destroy() {
265
266 histogram.destroy();
267 return potential.destroy();
268 }
269
270
271
272
273 public double energy(double[] x) {
274
275
276 if (state == Potential.STATE.FAST) {
277 forceFieldEnergy = potential.energy(x);
278 return forceFieldEnergy;
279 }
280
281
282 if (propagateLambda) {
283 histogram.stochasticPreForce();
284 }
285
286
287 fill(tempGradient, 0.0);
288 forceFieldEnergy = potential.energyAndGradient(x, tempGradient);
289
290 dForceFieldEnergydL = lambdaInterface.getdEdL();
291 d2UdL2 = lambdaInterface.getd2EdL2();
292 int lambdaBin = histogram.indexForLambda();
293 dUdLambda = dForceFieldEnergydL;
294
295 gLdEdL = 0.0;
296 double bias1D;
297
298 histogram.updateFreeEnergyDifference(false, false);
299 if (histogram.hd.metaDynamics) {
300 bias1D = histogram.energyAndGradientMeta(true);
301 } else {
302
303 if (histogram.hd.biasMag > 0.0) {
304 double[] chainRule = new double[2];
305 gLdEdL = histogram.energyAndGradient2D(dUdLambda, chainRule);
306 double dGdLambda = chainRule[0];
307 double dGdFLambda = chainRule[1];
308 dUdLambda += dGdLambda + dGdFLambda * d2UdL2;
309 }
310
311
312 bias1D = histogram.energyAndGradient1D(true);
313 }
314
315
316 biasEnergy = bias1D + gLdEdL;
317
318 if (print) {
319 logger.info(format(" Bias Energy %16.8f", biasEnergy));
320 logger.info(format(" %s %16.8f (Kcal/mole)", "OST Potential ", forceFieldEnergy + biasEnergy));
321 }
322
323 if (propagateLambda) {
324 histogram.stochasticPostForce();
325
326 histogram.ld.stepsTaken++;
327 long energyCount = histogram.ld.stepsTaken;
328
329
330 int printFrequency = dynamicsOptions.getReportFrequency(100);
331 if (energyCount % printFrequency == 0) {
332 double dBdL = dUdLambda - dForceFieldEnergydL;
333 double lambda = histogram.ld.lambda;
334 int lambdaBins = histogram.hd.getLambdaBins();
335 if (lambdaBins < 1000) {
336 logger.info(format(" L=%6.4f (%3d) F_LU=%10.4f F_LB=%10.4f F_L=%10.4f V_L=%10.4f", lambda,
337 lambdaBin, dForceFieldEnergydL, dBdL, dUdLambda, histogram.ld.thetaVelocity));
338 } else {
339 logger.info(format(" L=%6.4f (%4d) F_LU=%10.4f F_LB=%10.4f F_L=%10.4f V_L=%10.4f", lambda,
340 lambdaBin, dForceFieldEnergydL, dBdL, dUdLambda, histogram.ld.thetaVelocity));
341 }
342 }
343
344
345 if (energyCount % histogram.hd.countInterval == 0) {
346 histogram.addBias(dForceFieldEnergydL);
347
348
349 if (optimizationParameters.doOptimization) {
350 optimizationParameters.optimize(forceFieldEnergy, x, tempGradient);
351 }
352
353 if (algorithmListener != null) {
354 algorithmListener.algorithmUpdate(molecularAssembly);
355 }
356 }
357 }
358
359 totalEnergy = forceFieldEnergy + biasEnergy;
360
361 return totalEnergy;
362 }
363
364
365
366
367 @Override
368 public double energyAndGradient(double[] x, double[] gradient) {
369
370
371 if (state != STATE.FAST && propagateLambda) {
372 histogram.stochasticPreForce();
373 }
374
375
376 forceFieldEnergy = potential.energyAndGradient(x, gradient);
377
378
379 if (state == STATE.FAST) {
380 return forceFieldEnergy;
381 }
382
383
384 dForceFieldEnergydL = lambdaInterface.getdEdL();
385 dUdLambda = dForceFieldEnergydL;
386 d2UdL2 = lambdaInterface.getd2EdL2();
387
388 gLdEdL = 0.0;
389 double bias1D;
390
391 histogram.updateFreeEnergyDifference(false, false);
392 if (histogram.hd.metaDynamics) {
393 bias1D = histogram.energyAndGradientMeta(true);
394 } else {
395 if (histogram.hd.biasMag > 0) {
396 double[] chainRule = new double[2];
397 gLdEdL = histogram.energyAndGradient2D(dUdLambda, chainRule);
398 double dGdLambda = chainRule[0];
399 double dGdFLambda = chainRule[1];
400
401
402 dUdLambda += dGdLambda + dGdFLambda * d2UdL2;
403
404
405 fill(dUdXdL, 0.0);
406 lambdaInterface.getdEdXdL(dUdXdL);
407 for (int i = 0; i < nVariables; i++) {
408 gradient[i] += dGdFLambda * dUdXdL[i];
409 }
410 }
411
412
413 bias1D = histogram.energyAndGradient1D(true);
414 }
415
416
417 biasEnergy = bias1D + gLdEdL;
418
419 if (print) {
420 logger.info(format(" %s %16.8f", "Bias Energy ", biasEnergy));
421 logger.info(format(" %s %16.8f %s", "OST Potential ", forceFieldEnergy + biasEnergy, "(Kcal/mole)"));
422 }
423
424 if (propagateLambda) {
425 histogram.stochasticPostForce();
426
427 histogram.ld.stepsTaken++;
428 long energyCount = histogram.ld.stepsTaken;
429
430
431 int printFrequency = dynamicsOptions.getReportFrequency(100);
432 if (energyCount % printFrequency == 0) {
433 double dBdL = dUdLambda - dForceFieldEnergydL;
434 int lambdaBin = histogram.indexForLambda();
435 double lambda = histogram.ld.lambda;
436 int lambdaBins = histogram.hd.getLambdaBins();
437 if (lambdaBins < 1000) {
438 logger.info(format(" L=%6.4f (%3d) F_LU=%10.4f F_LB=%10.4f F_L=%10.4f V_L=%10.4f", lambda,
439 lambdaBin, dForceFieldEnergydL, dBdL, dUdLambda, histogram.ld.thetaVelocity));
440 } else {
441 logger.info(format(" L=%6.4f (%4d) F_LU=%10.4f F_LB=%10.4f F_L=%10.4f V_L=%10.4f", lambda,
442 lambdaBin, dForceFieldEnergydL, dBdL, dUdLambda, histogram.ld.thetaVelocity));
443 }
444 }
445
446
447 if (energyCount % histogram.hd.countInterval == 0) {
448 histogram.addBias(dForceFieldEnergydL);
449
450
451 if (optimizationParameters.doOptimization) {
452 optimizationParameters.optimize(forceFieldEnergy, x, gradient);
453 }
454
455 if (algorithmListener != null) {
456 algorithmListener.algorithmUpdate(molecularAssembly);
457 }
458 }
459 }
460
461 totalEnergy = forceFieldEnergy + biasEnergy;
462
463 return totalEnergy;
464 }
465
466
467
468
469 @Override
470 public double[] getAcceleration(double[] acceleration) {
471 return potential.getAcceleration(acceleration);
472 }
473
474 public Histogram[] getAllHistograms() {
475 int nHisto = allHistograms.size();
476 Histogram[] ret = new Histogram[nHisto];
477 ret = allHistograms.toArray(ret);
478 return ret;
479 }
480
481
482
483
484 @Override
485 public double[] getCoordinates(double[] doubles) {
486 return potential.getCoordinates(doubles);
487 }
488
489
490
491
492 @Override
493 public void setCoordinates(double[] doubles) {
494 potential.setCoordinates(doubles);
495 }
496
497
498
499
500 @Override
501 public Crystal getCrystal() {
502 return potential.getCrystal();
503 }
504
505
506
507
508 @Override
509 public void setCrystal(Crystal crystal) {
510 potential.setCrystal(crystal);
511 }
512
513
514
515
516
517
518
519 public long getEnergyCount() {
520 return histogram.ld.stepsTaken;
521 }
522
523
524
525
526 @Override
527 public Potential.STATE getEnergyTermState() {
528 return state;
529 }
530
531
532
533
534 @Override
535 public void setEnergyTermState(Potential.STATE state) {
536 this.state = state;
537 potential.setEnergyTermState(state);
538 }
539
540
541
542
543
544
545 public double getForceFieldEnergy() {
546 return forceFieldEnergy;
547 }
548
549
550
551
552
553
554 public Histogram getHistogram() {
555 return histogram;
556 }
557
558
559
560
561
562
563 public double getLambda() {
564 return histogram.ld.lambda;
565 }
566
567
568
569
570
571
572 public void setLambda(double lambda) {
573 if (histogram != null) {
574 lambda = histogram.mapLambda(lambda);
575 } else {
576 logger.warning(" OrthogonalSpaceTempering.setLambda was called before histogram constructed!");
577 logger.info(Utilities.stackTraceToString(new RuntimeException()));
578 }
579 lambdaInterface.setLambda(lambda);
580 histogram.ld.lambda = lambda;
581 histogram.ld.theta = asin(sqrt(lambda));
582 }
583
584
585
586
587 @Override
588 public double[] getMass() {
589 return potential.getMass();
590 }
591
592
593
594
595 @Override
596 public int getNumberOfVariables() {
597 return potential.getNumberOfVariables();
598 }
599
600
601
602
603
604
605 public OptimizationParameters getOptimizationParameters() {
606 return optimizationParameters;
607 }
608
609
610
611
612
613
614 public Potential getPotentialEnergy() {
615 return potential;
616 }
617
618
619
620
621 @Override
622 public double[] getPreviousAcceleration(double[] previousAcceleration) {
623 return potential.getPreviousAcceleration(previousAcceleration);
624 }
625
626
627
628
629 @Override
630 public double[] getScaling() {
631 return potential.getScaling();
632 }
633
634
635
636
637 @Override
638 public void setScaling(double[] scaling) {
639 potential.setScaling(scaling);
640 }
641
642
643
644
645 @Override
646 public double getTotalEnergy() {
647 return totalEnergy;
648 }
649
650
651
652
653
654
655 public double getTotaldEdLambda() {
656 return dUdLambda;
657 }
658
659
660
661
662
663
664 @Override
665 public Potential.VARIABLE_TYPE[] getVariableTypes() {
666 return potential.getVariableTypes();
667 }
668
669
670
671
672 @Override
673 public double[] getVelocity(double[] velocity) {
674 return potential.getVelocity(velocity);
675 }
676
677
678
679
680 @Override
681 public double getd2EdL2() {
682 throw new UnsupportedOperationException(
683 " Second derivatives of the bias are not implemented, as they require third derivatives of the potential.");
684 }
685
686
687
688
689 @Override
690 public double getdEdL() {
691 return getTotaldEdLambda();
692 }
693
694
695
696
697 @Override
698 public void getdEdXdL(double[] gradient) {
699 throw new UnsupportedOperationException(
700 " Second derivatives of the bias are not implemented, as they require third derivatives of the potential.");
701 }
702
703
704 public void logOutputFiles(int index) {
705 logger.info(format(" OST: Lambda file %s, histogram %s", histogram.ld.getLambdaFile(),
706 allHistograms.get(index).hd.getHistogramFile()));
707 }
708
709
710
711
712 @Override
713 public void setAcceleration(double[] acceleration) {
714 potential.setAcceleration(acceleration);
715 }
716
717
718
719
720
721
722
723 public void setHardWallConstraint(boolean hardWallConstraint) {
724 this.hardWallConstraint = hardWallConstraint;
725 }
726
727 public void setMolecularAssembly(MolecularAssembly molecularAssembly) {
728 this.molecularAssembly = molecularAssembly;
729 }
730
731
732
733
734 @Override
735 public void setPreviousAcceleration(double[] previousAcceleration) {
736 potential.setPreviousAcceleration(previousAcceleration);
737 }
738
739
740
741
742
743
744 public void setPropagateLambda(boolean propagateLambda) {
745 this.propagateLambda = propagateLambda;
746 }
747
748
749
750
751 public boolean getPropagateLambda() {
752 return propagateLambda;
753 }
754
755
756
757
758 @Override
759 public void setVelocity(double[] velocity) {
760 potential.setVelocity(velocity);
761 }
762
763
764
765
766
767
768 public void switchHistogram(int index) {
769 histogramIndex = index;
770 histogram = allHistograms.get(histogramIndex);
771 logger.info(" OST switching to histogram " + histogramIndex);
772 }
773
774 @Override
775 public void writeAdditionalRestartInfo(boolean recursive) {
776 histogram.writeRestart();
777 if (recursive) {
778 potential.writeAdditionalRestartInfo(recursive);
779 }
780 }
781
782 double getLambdaWriteOut() {
783 return histogram.hd.resetHistogramAtLambda;
784 }
785
786
787
788
789
790
791 double getForceFielddEdL() {
792 return dForceFieldEnergydL;
793 }
794
795
796
797
798
799
800 double getBiasEnergy() {
801 return biasEnergy;
802 }
803
804
805
806
807
808
809
810
811
812
813 boolean insideHardWallConstraint(double lambda, double dUdL) {
814 if (hardWallConstraint) {
815 double weight = histogram.getRecursionKernelValue(lambda, dUdL);
816 return weight > 0.0;
817 }
818 return true;
819 }
820
821
822
823
824 public class OptimizationParameters {
825
826
827
828
829
830
831 private boolean doOptimization = false;
832
833
834
835 private final boolean doUnitCellReset;
836
837
838
839
840
841 private final double lambdaCutoff;
842
843
844
845
846
847 private double optimumEnergy = Double.MAX_VALUE;
848
849
850
851
852
853 private final int frequency;
854
855
856
857
858
859 private final double eps;
860
861
862
863
864
865 private final double tolerance;
866
867
868
869
870
871 private final double energyWindow;
872
873
874
875 private double[] optimumCoords;
876
877
878
879 private File optimizationFile;
880
881
882
883 private SystemFilter optimizationFilter;
884
885
886
887
888 OptimizationParameters(CompositeConfiguration properties) {
889 energyWindow = properties.getDouble("ost-opt-energy-window", 10.0);
890 eps = properties.getDouble("ost-opt-eps", 0.1);
891 tolerance = properties.getDouble("ost-opt-tolerance", 1.0e-8);
892 frequency = properties.getInt("ost-opt-frequency", 10000);
893 lambdaCutoff = properties.getDouble("ost-opt-lambda-cutoff", 0.8);
894 doUnitCellReset = properties.getBoolean("ost-opt-unitcell-reset", false);
895 }
896
897 private void log() {
898 logger.info("\n Optimization Parameters");
899 logger.info(format(" Energy Window: %6.3f (kcal/mol)", energyWindow));
900 logger.info(format(" EPS: %6.4f RMS (kcal/mol/Å)", eps));
901 logger.info(format(" Tolerance: %6.4f (kcal/mol)", tolerance));
902 logger.info(format(" Frequency: %6d (steps)", frequency));
903 logger.info(format(" Lambda Cutoff: %6.4f", lambdaCutoff));
904 logger.info(format(" Unit Cell Reset: %6B", doUnitCellReset));
905 logger.info(format(" File: %s", optimizationFile.getName()));
906 }
907
908
909
910
911
912
913 public double[] getOptimumCoordinates() {
914 if (optimumEnergy < Double.MAX_VALUE) {
915 return optimumCoords;
916 } else {
917 logger.info("Lambda optimization cutoff was not reached. Try increasing the number of timesteps.");
918 return null;
919 }
920 }
921
922
923
924
925
926
927 public double getOptimumEnergy() {
928 if (optimumEnergy == Double.MAX_VALUE) {
929 logger.info(
930 "Lambda optimization cutoff was not reached. Try increasing the number of timesteps.");
931 }
932 return optimumEnergy;
933 }
934
935
936
937
938
939
940
941
942 public void optimize(double e, double[] x, @Nullable double[] gradient) {
943
944
945 double lambda = histogram.ld.lambda;
946 long stepsTaken = histogram.ld.stepsTaken;
947 if (doOptimization && lambda > lambdaCutoff && stepsTaken % frequency == 0) {
948 if (gradient == null) {
949 gradient = new double[x.length];
950 }
951 } else {
952 return;
953 }
954
955 logger.info(format("\n OST Minimization (Step %d)", stepsTaken));
956
957
958 lambdaInterface.setLambda(1.0);
959
960
961 potential.setEnergyTermState(Potential.STATE.BOTH);
962
963
964 try {
965 double startingEnergy = potential.energy(x);
966 Minimize minimize = new Minimize(molecularAssembly, potential, algorithmListener);
967 minimize.minimize(eps);
968
969 double minEnergy = potential.getTotalEnergy();
970
971 if (minEnergy < optimumEnergy + energyWindow) {
972 if (minEnergy < optimumEnergy) {
973 optimumEnergy = minEnergy;
974 }
975 int n = potential.getNumberOfVariables();
976 optimumCoords = new double[n];
977 optimumCoords = potential.getCoordinates(optimumCoords);
978 double mass = molecularAssembly.getMass();
979 Crystal crystal = molecularAssembly.getCrystal();
980 double density = crystal.getDensity(mass);
981 optimizationFilter.writeFile(optimizationFile, true);
982 Crystal uc = crystal.getUnitCell();
983 logger.info(format(" Minimum: %12.6f %s (%12.6f g/cc) optimized from %12.6f at step %d.",
984 minEnergy, uc.toShortString(), density, startingEnergy, stepsTaken));
985 }
986 } catch (Exception ex) {
987 String message = ex.getMessage();
988 logger.info(
989 format(" Exception minimizing coordinates at lambda=%8.6f\n %s.", lambda, message));
990 logger.info(" Sampling will continue.");
991 }
992
993
994 lambdaInterface.setLambda(lambda);
995
996
997 potential.setEnergyTermState(state);
998
999 if (doUnitCellReset) {
1000 logger.info("\n Resetting Unit Cell");
1001 double mass = molecularAssembly.getMass();
1002 double density = molecularAssembly.getCrystal().getDensity(mass);
1003 molecularAssembly.applyRandomDensity(density);
1004 molecularAssembly.applyRandomSymOp(0.0);
1005 lambda = 0.0;
1006 lambdaInterface.setLambda(lambda);
1007 } else {
1008
1009 double eCheck = potential.energyAndGradient(x, gradient);
1010
1011 if (abs(eCheck - e) > tolerance) {
1012 logger.warning(format(" Optimization could not revert coordinates %16.8f vs. %16.8f.", e, eCheck));
1013 }
1014 }
1015 }
1016
1017
1018
1019
1020
1021
1022
1023 public void setOptimization(boolean doOptimization, MolecularAssembly molecularAssembly) {
1024 this.doOptimization = doOptimization;
1025 OrthogonalSpaceTempering.this.molecularAssembly = molecularAssembly;
1026 File file = molecularAssembly.getFile();
1027 String fileName = FilenameUtils.removeExtension(file.getAbsolutePath());
1028 String ext = FilenameUtils.getExtension(file.getAbsolutePath());
1029 if (optimizationFilter == null) {
1030 if (ext.toUpperCase().contains("XYZ")) {
1031 optimizationFile = new File(fileName + "_opt.arc");
1032 optimizationFilter = new XYZFilter(optimizationFile, molecularAssembly,
1033 molecularAssembly.getForceField(), molecularAssembly.getProperties());
1034 } else {
1035 optimizationFile = new File(fileName + "_opt.pdb");
1036 PDBFilter pdbFilter = new PDBFilter(optimizationFile, molecularAssembly,
1037 molecularAssembly.getForceField(), molecularAssembly.getProperties());
1038 int models = pdbFilter.countNumModels();
1039 pdbFilter.setModelNumbering(models);
1040 optimizationFilter = pdbFilter;
1041 }
1042 }
1043
1044 if (this.doOptimization) {
1045 log();
1046 }
1047 }
1048 }
1049
1050
1051
1052
1053
1054
1055
1056 public class Histogram {
1057
1058
1059
1060
1061 private static final double TWO_D_NORMALIZATION = 1.0;
1062
1063
1064
1065
1066 private static final double ONE_D_NORMALIZATION = Math.sqrt(2.0 * Math.PI);
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076 private static final double PSEUDO_BIAS_MAGNITUDE = 1.0;
1077
1078
1079
1080 protected final Comm world;
1081
1082
1083
1084 protected final int rank;
1085
1086
1087
1088 final double[] ensembleAveragedUdL;
1089
1090
1091
1092
1093
1094
1095 private final double deltaT;
1096
1097
1098
1099 private final IntegrationType integrationType;
1100
1101
1102
1103 private final SendAsynchronous sendAsynchronous;
1104
1105
1106
1107 private final SendSynchronous sendSynchronous;
1108
1109
1110
1111
1112 private double temperingWeight = 1.0;
1113
1114
1115
1116
1117
1118 private double[] kernelValues;
1119
1120
1121
1122 private double lastReceivedLambda;
1123
1124
1125
1126 private double lastReceiveddUdL;
1127 private final boolean spreadBias;
1128
1129
1130
1131 final HistogramData hd;
1132
1133
1134
1135 final LambdaData ld;
1136
1137
1138
1139 private final Stochastic stochastic;
1140
1141
1142
1143 private final SystemState lambdaState;
1144
1145
1146
1147 private int currentNumberOfHills = 0;
1148
1149
1150
1151 private double currentFreeEnergyDifference = 0.0;
1152
1153
1154
1155
1156
1157
1158
1159 Histogram(CompositeConfiguration properties, HistogramData histogramData, LambdaData lambdaData) {
1160 hd = histogramData;
1161 ld = lambdaData;
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175 deltaT = hd.temperingFactor * R * dynamicsOptions.getTemperature();
1176
1177
1178 ensembleAveragedUdL = new double[hd.getLambdaBins()];
1179
1180
1181 kernelValues = new double[hd.getDUDLBins()];
1182
1183 String propString = properties.getString("ost-integrationType", "SIMPSONS");
1184 IntegrationType testType;
1185 try {
1186 testType = IntegrationType.valueOf(propString.toUpperCase());
1187 } catch (Exception ex) {
1188 logger.warning(format(" Invalid argument %s to ost-integrationType; resetting to SIMPSONS", propString));
1189 testType = SIMPSONS;
1190 }
1191 integrationType = testType;
1192
1193 spreadBias = properties.getBoolean("ost-spread-bias", false);
1194
1195
1196
1197
1198
1199 world = Comm.world();
1200 int numProc = world.size();
1201 rank = world.rank();
1202 if (hd.asynchronous) {
1203
1204 sendAsynchronous = new SendAsynchronous(this);
1205 sendAsynchronous.start();
1206 sendSynchronous = null;
1207 } else {
1208 Histogram[] histograms = new Histogram[numProc];
1209 int[] rankToHistogramMap = new int[numProc];
1210 for (int i = 0; i < numProc; i++) {
1211 histograms[i] = this;
1212 rankToHistogramMap[i] = 0;
1213 }
1214 sendSynchronous = new SendSynchronous(histograms, rankToHistogramMap);
1215 sendAsynchronous = null;
1216 }
1217
1218 lastReceivedLambda = ld.lambda;
1219 if (hd.discreteLambda) {
1220 lastReceivedLambda = mapLambda(lastReceivedLambda);
1221 logger.info(format(" Discrete lambda: initializing lambda to nearest bin %.5f", lastReceivedLambda));
1222 ld.lambda = lastReceivedLambda;
1223 ld.theta = asin(sqrt(lastReceivedLambda));
1224 lambdaInterface.setLambda(lastReceivedLambda);
1225 lambdaState = null;
1226 stochastic = null;
1227 } else {
1228
1229 lambdaState = new SystemState(1);
1230 stochastic = new Stochastic(lambdaParticleOptions.getLambdaFriction(), lambdaState);
1231 stochastic.setTemperature(dynamicsOptions.getTemperature());
1232 stochastic.setTimeStep(dynamicsOptions.getDtPsec());
1233 double[] mass = lambdaState.getMass();
1234 double[] thetaPosition = lambdaState.x();
1235 double[] thetaVelocity = lambdaState.v();
1236 double[] thetaAccel = lambdaState.a();
1237 mass[0] = lambdaParticleOptions.getLambdaMass();
1238 thetaPosition[0] = ld.theta;
1239 thetaVelocity[0] = ld.thetaVelocity;
1240 thetaAccel[0] = ld.thetaAcceleration;
1241 }
1242
1243 lastReceiveddUdL = getdEdL();
1244
1245 if (hd.wasHistogramRead()) {
1246 updateFreeEnergyDifference(true, false);
1247 }
1248 }
1249
1250 public void disableResetStatistics() {
1251 hd.resetHistogram = false;
1252 }
1253
1254
1255
1256
1257
1258
1259
1260 public StringBuffer evaluateTotalOSTBias(boolean bias) {
1261 StringBuffer sb = new StringBuffer();
1262 double[] chainRule = new double[2];
1263 for (int dUdLBin = 0; dUdLBin < hd.getDUDLBins(); dUdLBin++) {
1264 double currentdUdL = dUdLforBin(dUdLBin);
1265 sb.append(format(" %16.8f", currentdUdL));
1266 for (int lambdaBin = 0; lambdaBin < hd.getLambdaBins(); lambdaBin++) {
1267 double currentLambda = lambdaForIndex(lambdaBin);
1268 double bias1D = energyAndGradient1D(currentLambda, false);
1269 double bias2D = energyAndGradient2D(currentLambda, currentdUdL, chainRule, hd.biasMag);
1270 double totalBias = bias1D + bias2D;
1271
1272 if (!bias) {
1273 totalBias = -totalBias;
1274 }
1275 sb.append(format(" %16.8f", totalBias));
1276 }
1277 sb.append("\n");
1278 }
1279 return sb;
1280 }
1281
1282
1283
1284
1285
1286
1287
1288 public StringBuffer evaluate2DOSTBias(boolean bias) {
1289 StringBuffer sb = new StringBuffer();
1290 double[] chainRule = new double[2];
1291 for (int dUdLBin = 0; dUdLBin < hd.getDUDLBins(); dUdLBin++) {
1292 double currentdUdL = dUdLforBin(dUdLBin);
1293 sb.append(format(" %16.8f", currentdUdL));
1294 for (int lambdaBin = 0; lambdaBin < hd.getLambdaBins(); lambdaBin++) {
1295 double currentLambda = lambdaForIndex(lambdaBin);
1296 double bias2D = energyAndGradient2D(currentLambda, currentdUdL, chainRule, hd.biasMag);
1297 if (!bias) {
1298 bias2D = -bias2D;
1299 }
1300 sb.append(format(" %16.8f", bias2D));
1301 }
1302 sb.append("\n");
1303 }
1304 return sb;
1305 }
1306
1307
1308
1309
1310
1311
1312
1313 public boolean getIndependentWalkers() {
1314 return hd.independentWalkers;
1315 }
1316
1317 public double getLambdaResetValue() {
1318 return hd.resetHistogramAtLambda;
1319 }
1320
1321
1322
1323
1324
1325
1326 public int getRank() {
1327 return rank;
1328 }
1329
1330 public boolean getResetStatistics() {
1331 return hd.resetHistogram;
1332 }
1333
1334
1335
1336
1337
1338
1339 public Optional<SendSynchronous> getSynchronousSend() {
1340 return Optional.ofNullable(sendSynchronous);
1341 }
1342
1343 public void setLastReceiveddUdL(double lastReceiveddUdL) {
1344 this.lastReceiveddUdL = lastReceiveddUdL;
1345 }
1346
1347 public double updateFreeEnergyDifference(boolean print, boolean save) {
1348 if (hd.metaDynamics) {
1349 return updateMetaDynamicsFreeEnergyDifference(print, save);
1350 } else {
1351 return updateOSTFreeEnergyDifference(print, save);
1352 }
1353 }
1354
1355
1356
1357
1358
1359
1360
1361
1362 public double updateMetaDynamicsFreeEnergyDifference(boolean print, boolean save) {
1363 synchronized (this) {
1364 if (!print && currentNumberOfHills == hd.counts) {
1365 return currentFreeEnergyDifference;
1366 }
1367 double freeEnergyDifferenceMeta = 0.0;
1368 double freeEnergyDifferenceTI = 0.0;
1369
1370 double minFL = Double.MAX_VALUE;
1371
1372 int lambdaBins = hd.getLambdaBins();
1373 double[] metaFreeEnergy = new double[lambdaBins];
1374
1375
1376 double totalWeight = 0;
1377 StringBuilder stringBuilder = new StringBuilder();
1378
1379
1380 for (int lambdaBin = 0; lambdaBin < lambdaBins; lambdaBin++) {
1381 int firstdUdLBin = firstdUdLBin(lambdaBin);
1382 int lastdUdLBin = lastdUdLBin(lambdaBin);
1383 double lambdaCount = 0;
1384
1385 double mindUdLForLambda = 0.0;
1386 double maxdUdLforLambda = 0.0;
1387 double maxBias = 0;
1388 if (firstdUdLBin == -1 || lastdUdLBin == -1) {
1389 ensembleAveragedUdL[lambdaBin] = 0.0;
1390 minFL = 0.0;
1391 } else {
1392 double ensembleAverageFLambda = 0.0;
1393 double partitionFunction = 0.0;
1394
1395
1396 double offset = evaluateKernelForLambda(lambdaBin, firstdUdLBin, lastdUdLBin);
1397
1398 for (int dUdLBin = firstdUdLBin; dUdLBin <= lastdUdLBin; dUdLBin++) {
1399 double kernel = kernelValues[dUdLBin];
1400
1401 if (kernel - offset > maxBias) {
1402 maxBias = kernel - offset;
1403 }
1404
1405
1406 partitionFunction += kernel;
1407
1408 double currentdUdL = dUdLforBin(dUdLBin);
1409 ensembleAverageFLambda += currentdUdL * kernel;
1410 lambdaCount += getRecursionKernelValue(lambdaBin, dUdLBin);
1411 }
1412 if (minFL > maxBias) {
1413 minFL = maxBias;
1414 }
1415 ensembleAveragedUdL[lambdaBin] = (partitionFunction == 0) ? 0 : ensembleAverageFLambda / partitionFunction;
1416 mindUdLForLambda = hd.dUdLMinimum + firstdUdLBin * hd.dUdLBinWidth;
1417 maxdUdLforLambda = hd.dUdLMinimum + (lastdUdLBin + 1) * hd.dUdLBinWidth;
1418 }
1419
1420 double deltaFreeEnergy = ensembleAveragedUdL[lambdaBin] * deltaForLambdaBin(lambdaBin);
1421 freeEnergyDifferenceTI += deltaFreeEnergy;
1422 totalWeight += lambdaCount;
1423
1424
1425 double lambdaBinWidth = hd.lambdaBinWidth;
1426 double llL = lambdaBin * lambdaBinWidth - hd.lambdaBinWidth_2;
1427 double ulL = llL + lambdaBinWidth;
1428 if (llL < 0.0) {
1429 llL = 0.0;
1430 }
1431 if (ulL > 1.0) {
1432 ulL = 1.0;
1433 }
1434
1435 double midLambda = llL;
1436 if (!hd.discreteLambda) {
1437 midLambda = (llL + ulL) / 2.0;
1438 }
1439 double bias1D = energyAndGradient1D(midLambda, false);
1440 metaFreeEnergy[lambdaBin] = energyAndGradientMeta(midLambda, false);
1441 freeEnergyDifferenceMeta = -(metaFreeEnergy[lambdaBin] - metaFreeEnergy[0]);
1442
1443 if (print || save) {
1444 stringBuilder.append(format(" %6.2e %7.5f %7.1f %7.1f %9.2f %9.2f %9.2f %9.2f %9.2f\n", lambdaCount,
1445 midLambda, mindUdLForLambda, maxdUdLforLambda, ensembleAveragedUdL[lambdaBin],
1446 bias1D, freeEnergyDifferenceTI, metaFreeEnergy[lambdaBin], freeEnergyDifferenceMeta));
1447 }
1448 }
1449
1450 double temperingOffset = hd.getTemperingOffset();
1451 double temperEnergy = (minFL > temperingOffset) ? temperingOffset - minFL : 0;
1452 temperingWeight = exp(temperEnergy / deltaT);
1453
1454 if (print) {
1455 logger.info(" Weight Lambda dU/dL Bins <dU/dL> g(L) dG_OST(L) Meta(L) dG_Meta(L)");
1456 logger.info(stringBuilder.toString());
1457 logger.info(" Histogram Evaluation");
1458 logger.info(format(" Free Energy Difference: %12.4f kcal/mol", freeEnergyDifferenceMeta));
1459 logger.info(format(" Number of Hills: %12d", hd.counts));
1460 logger.info(format(" Total Bias Added: %12.4f kcal/mol", totalWeight * hd.biasMag));
1461 logger.info(format(" Minimum Bias: %12.4f kcal/mol", minFL));
1462 logger.info(format(" Tempering Percentage: %12.4f %%\n", temperingWeight * 100));
1463 }
1464
1465 if (save) {
1466 String modelFilename = molecularAssembly.getFile().getAbsolutePath();
1467 File saveDir = new File(FilenameUtils.getFullPath(modelFilename));
1468 String dirName = saveDir + File.separator;
1469 String fileName = dirName + "histogram.txt";
1470 try {
1471 logger.info(" Writing " + fileName);
1472 PrintWriter printWriter = new PrintWriter(fileName);
1473 printWriter.write(stringBuilder.toString());
1474 printWriter.close();
1475 } catch (Exception e) {
1476 logger.info(format(" Failed to write %s.", fileName));
1477 }
1478 }
1479
1480 currentNumberOfHills = hd.counts;
1481 currentFreeEnergyDifference = freeEnergyDifferenceMeta;
1482 return currentFreeEnergyDifference;
1483 }
1484 }
1485
1486
1487
1488
1489
1490
1491
1492
1493 public double updateOSTFreeEnergyDifference(boolean print, boolean save) {
1494 synchronized (this) {
1495 if (!print && currentNumberOfHills == hd.counts) {
1496 return currentFreeEnergyDifference;
1497 }
1498
1499 double freeEnergyDifferenceOST = 0.0;
1500 double minFL = Double.MAX_VALUE;
1501
1502
1503
1504 boolean biasMagZero = hd.biasMag <= 0.0;
1505
1506
1507 double totalWeight = 0;
1508 double beta = 1.0 / (R * dynamicsOptions.getTemperature());
1509 StringBuilder stringBuilder = new StringBuilder();
1510
1511
1512 for (int lambdaBin = 0; lambdaBin < hd.lambdaBins; lambdaBin++) {
1513 int firstdUdLBin = firstdUdLBin(lambdaBin);
1514 int lastdUdLBin = lastdUdLBin(lambdaBin);
1515 double lambdaCount = 0;
1516
1517 double mindUdLforLambda = 0.0;
1518 double maxdUdLforLambda = 0.0;
1519 double maxBias = 0;
1520 if (firstdUdLBin == -1 || lastdUdLBin == -1) {
1521 ensembleAveragedUdL[lambdaBin] = 0.0;
1522 minFL = 0.0;
1523 } else {
1524 double ensembleAverage = 0.0;
1525 double partitionFunction = 0.0;
1526
1527
1528 double offset = evaluateKernelForLambda(lambdaBin, firstdUdLBin, lastdUdLBin);
1529
1530 for (int dUdLBin = firstdUdLBin; dUdLBin <= lastdUdLBin; dUdLBin++) {
1531 double kernel = kernelValues[dUdLBin];
1532
1533 if (kernel - offset > maxBias) {
1534 maxBias = kernel - offset;
1535 }
1536
1537 double weight;
1538 if (biasMagZero) {
1539
1540 weight = kernel;
1541 } else {
1542
1543 weight = exp(kernel * beta);
1544 }
1545 partitionFunction += weight;
1546
1547 double currentdUdL = dUdLforBin(dUdLBin);
1548 ensembleAverage += currentdUdL * weight;
1549 lambdaCount += getRecursionKernelValue(lambdaBin, dUdLBin);
1550 }
1551 if (minFL > maxBias) {
1552 minFL = maxBias;
1553 }
1554 ensembleAveragedUdL[lambdaBin] = (partitionFunction == 0) ? 0 : ensembleAverage / partitionFunction;
1555 mindUdLforLambda = hd.dUdLMinimum + firstdUdLBin * hd.dUdLBinWidth;
1556 maxdUdLforLambda = hd.dUdLMinimum + (lastdUdLBin + 1) * hd.dUdLBinWidth;
1557 }
1558
1559 double deltaFreeEnergy = ensembleAveragedUdL[lambdaBin] * deltaForLambdaBin(lambdaBin);
1560 freeEnergyDifferenceOST += deltaFreeEnergy;
1561 totalWeight += lambdaCount;
1562
1563 if (print || save) {
1564 double llL = lambdaBin * hd.lambdaBinWidth - hd.lambdaBinWidth_2;
1565 double ulL = llL + hd.lambdaBinWidth;
1566 if (llL < 0.0) {
1567 llL = 0.0;
1568 }
1569 if (ulL > 1.0) {
1570 ulL = 1.0;
1571 }
1572
1573 double midLambda = llL;
1574 if (!hd.discreteLambda) {
1575 midLambda = (llL + ulL) / 2.0;
1576 }
1577 double bias1D = energyAndGradient1D(midLambda, false);
1578
1579 double bias2D = 0.0;
1580 if (!biasMagZero) {
1581 bias2D = computeBiasEnergy(midLambda, ensembleAveragedUdL[lambdaBin]) - bias1D;
1582 }
1583
1584 stringBuilder.append(
1585 format(" %6.2e %7.5f %7.1f %7.1f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n", lambdaCount,
1586 midLambda, mindUdLforLambda, maxdUdLforLambda, ensembleAveragedUdL[lambdaBin],
1587 bias1D, bias2D, bias1D + bias2D, freeEnergyDifferenceOST, bias1D + bias2D + freeEnergyDifferenceOST));
1588 }
1589 }
1590
1591 if (!biasMagZero) {
1592 double temperingOffset = hd.getTemperingOffset();
1593 double temperEnergy = (minFL > temperingOffset) ? temperingOffset - minFL : 0;
1594 temperingWeight = exp(temperEnergy / deltaT);
1595 }
1596
1597 freeEnergyDifferenceOST = integrateNumeric(ensembleAveragedUdL, integrationType);
1598
1599 if (print) {
1600 logger.info(" Weight Lambda dU/dL Bins <dU/dL> g(L) f(L,<dU/dL>) Bias dG(L) Bias+dG(L)");
1601 logger.info(stringBuilder.toString());
1602 logger.info(" Histogram Evaluation");
1603 logger.info(format(" Free Energy Difference: %12.4f kcal/mol", freeEnergyDifferenceOST));
1604 logger.info(format(" Number of Hills: %12d", hd.counts));
1605 logger.info(format(" Total Bias Added: %12.4f kcal/mol", totalWeight * hd.biasMag));
1606 logger.info(format(" Minimum Bias: %12.4f kcal/mol", minFL));
1607 logger.info(format(" Tempering Percentage: %12.4f %%\n", temperingWeight * 100));
1608 }
1609
1610 if (save) {
1611 String modelFilename = molecularAssembly.getFile().getAbsolutePath();
1612 File saveDir = new File(FilenameUtils.getFullPath(modelFilename));
1613 String dirName = saveDir + File.separator;
1614 String fileName = dirName + "histogram.txt";
1615 try {
1616 logger.info("\n Writing " + fileName);
1617 PrintWriter printWriter = new PrintWriter(fileName);
1618 printWriter.write(stringBuilder.toString());
1619 printWriter.close();
1620 } catch (Exception e) {
1621 logger.info(format(" Failed to write %s.", fileName));
1622 }
1623 }
1624
1625 currentNumberOfHills = hd.counts;
1626 currentFreeEnergyDifference = freeEnergyDifferenceOST;
1627 return currentFreeEnergyDifference;
1628 }
1629 }
1630
1631
1632
1633
1634
1635
1636
1637 private double deltaForLambdaBin(int lambdaBin) {
1638 if (!hd.discreteLambda && (lambdaBin == 0 || lambdaBin == hd.lambdaBins - 1)) {
1639
1640 return hd.lambdaBinWidth_2;
1641 } else if (hd.discreteLambda && lambdaBin == 0) {
1642
1643 return 0.0;
1644 }
1645
1646 return hd.lambdaBinWidth;
1647 }
1648
1649
1650
1651
1652
1653
1654
1655
1656 private int firstdUdLBin(int lambdaBin) {
1657
1658 synchronized (this) {
1659
1660 for (int jFL = 0; jFL < hd.dUdLBins; jFL++) {
1661 double count = hd.zHistogram[lambdaBin][jFL];
1662 if (count > 0) {
1663 return jFL;
1664 }
1665 }
1666 return -1;
1667 }
1668 }
1669
1670
1671
1672
1673
1674
1675
1676
1677 private int lastdUdLBin(int lambdaBin) {
1678
1679 synchronized (this) {
1680
1681 for (int jFL = hd.dUdLBins - 1; jFL >= 0; jFL--) {
1682 double count = hd.zHistogram[lambdaBin][jFL];
1683 if (count > 0) {
1684 return jFL;
1685 }
1686 }
1687 return -1;
1688 }
1689 }
1690
1691
1692
1693
1694
1695
1696 void writeRestart() {
1697 if (rank == 0 || hd.independentWrite) {
1698 updateFreeEnergyDifference(true, false);
1699 try {
1700 hd.writeHistogram();
1701 logger.info(format(" Wrote histogram restart to: %s.", hd.getHistogramFileName()));
1702 } catch (Exception ex) {
1703 String message = format(" Exception writing histogram restart file %s.", hd.getHistogramFileName());
1704 logger.log(Level.INFO, Utilities.stackTraceToString(ex));
1705 logger.log(Level.SEVERE, message, ex);
1706 }
1707 }
1708
1709
1710 try {
1711 ld.writeLambdaData();
1712 logger.info(format(" Wrote lambda restart to: %s.", ld.getLambdaFileName()));
1713 } catch (Exception ex) {
1714 String message = format(" Exception writing lambda restart file %s.", ld.getLambdaFileName());
1715 logger.log(Level.INFO, Utilities.stackTraceToString(ex));
1716 logger.log(Level.SEVERE, message, ex);
1717 }
1718 }
1719
1720 private double mapLambda(double lambda) {
1721 if (hd.discreteLambda) {
1722 return hd.lambdaLadder[indexForDiscreteLambda(lambda)];
1723 } else {
1724 return lambda;
1725 }
1726 }
1727
1728
1729
1730
1731
1732
1733
1734
1735 int indexForLambda(double lambda) {
1736 if (hd.discreteLambda) {
1737 return indexForDiscreteLambda(lambda);
1738 } else {
1739 return indexForContinuousLambda(lambda);
1740 }
1741 }
1742
1743 int indexForLambda() {
1744 return indexForLambda(ld.lambda);
1745 }
1746
1747 private double lambdaForIndex(int bin) {
1748 if (hd.discreteLambda) {
1749 return hd.lambdaLadder[bin];
1750 } else {
1751 return bin * hd.lambdaBinWidth;
1752 }
1753 }
1754
1755 private int indexForContinuousLambda(double lambda) {
1756 int lambdaBin = (int) floor((lambda - hd.minLambda) / hd.lambdaBinWidth);
1757 if (lambdaBin < 0) {
1758 lambdaBin = 0;
1759 }
1760 if (lambdaBin >= hd.lambdaBins) {
1761 lambdaBin = hd.lambdaBins - 1;
1762 }
1763 return lambdaBin;
1764 }
1765
1766 private int indexForDiscreteLambda(double lambda) {
1767 assert hd.discreteLambda && hd.lambdaLadder != null && hd.lambdaLadder.length > 0;
1768
1769 int initialGuess = indexForContinuousLambda(lambda);
1770 double minErr = Double.MAX_VALUE;
1771 int minErrBin = -1;
1772 for (int i = -1; i < 2; i++) {
1773 int guessBin = i + initialGuess;
1774 if (guessBin < 0 || guessBin >= hd.lambdaBins) {
1775 continue;
1776 }
1777 double guessLam = hd.lambdaLadder[guessBin];
1778 double guessErr = Math.abs(guessLam - lambda);
1779 if (guessErr < minErr) {
1780 minErr = guessErr;
1781 minErrBin = guessBin;
1782 }
1783 }
1784
1785 assert minErr < 1.0E-6;
1786 return minErrBin;
1787 }
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797 int binFordUdL(double dUdL) {
1798
1799
1800 if (dUdL < hd.dUdLMinimum) {
1801 return -1;
1802 }
1803
1804
1805 if (dUdL > hd.dUdLMaximum) {
1806 return -1;
1807 }
1808
1809 int bin = (int) floor((dUdL - hd.dUdLMinimum) / hd.dUdLBinWidth);
1810
1811 if (bin == hd.dUdLBins) {
1812 bin = hd.dUdLBins - 1;
1813 }
1814
1815 if (bin < 0) {
1816 bin = 0;
1817 }
1818
1819 return bin;
1820 }
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830 double getRecursionKernelValue(int lambdaBin, int dUdLBin) {
1831
1832 synchronized (this) {
1833
1834 lambdaBin = lambdaMirror(lambdaBin);
1835
1836
1837 if (dUdLBin < 0 || dUdLBin >= hd.dUdLBins) {
1838 return 0.0;
1839 }
1840
1841 return hd.zHistogram[lambdaBin][dUdLBin];
1842 }
1843 }
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853 double getRecursionKernelValue(double lambda, double dUdL) {
1854 return getRecursionKernelValue(indexForLambda(lambda), binFordUdL(dUdL));
1855 }
1856
1857
1858
1859
1860
1861
1862
1863
1864 void addToRecursionKernelValue(double currentLambda, double currentdUdL, double value) {
1865 synchronized (this) {
1866 if (spreadBias) {
1867
1868 int dUdLbiasCutoff = hd.dUdLBiasCutoff;
1869 checkRecursionKernelSize(dUdLforBin(binFordUdL(currentdUdL) - dUdLbiasCutoff));
1870 checkRecursionKernelSize(dUdLforBin(binFordUdL(currentdUdL) + dUdLbiasCutoff));
1871
1872 int currentLambdaBin = indexForLambda(currentLambda);
1873 int currentdUdLBin = binFordUdL(currentdUdL);
1874
1875
1876 double invLs2 = 0.5 / hd.lambdaVariance;
1877 double invFLs2 = 0.5 / hd.dUdLVariance;
1878
1879
1880 double normalize = 0.0;
1881 int lambdaBiasCutoff = hd.lambdaBiasCutoff;
1882 for (int iL = -lambdaBiasCutoff; iL <= lambdaBiasCutoff; iL++) {
1883 int lambdaBin = currentLambdaBin + iL;
1884 double deltaL = currentLambda - lambdaBin * hd.lambdaBinWidth;
1885 double deltaL2 = deltaL * deltaL;
1886
1887 double L2exp = exp(-deltaL2 * invLs2);
1888 for (int jFL = -dUdLbiasCutoff; jFL <= dUdLbiasCutoff; jFL++) {
1889 int dUdLBin = currentdUdLBin + jFL;
1890 double deltaFL = currentdUdL - dUdLforBin(dUdLBin);
1891 double deltaFL2 = deltaFL * deltaFL;
1892 normalize += L2exp * exp(-deltaFL2 * invFLs2);
1893 }
1894 }
1895
1896 for (int iL = -lambdaBiasCutoff; iL <= lambdaBiasCutoff; iL++) {
1897 int lambdaBin = currentLambdaBin + iL;
1898 double deltaL = currentLambda - lambdaBin * hd.lambdaBinWidth;
1899 double deltaL2 = deltaL * deltaL;
1900
1901 double L2exp = exp(-deltaL2 * invLs2);
1902 lambdaBin = lambdaMirror(lambdaBin);
1903 for (int jFL = -dUdLbiasCutoff; jFL <= dUdLbiasCutoff; jFL++) {
1904 int dUdLBin = currentdUdLBin + jFL;
1905 double deltaFL = currentdUdL - dUdLforBin(dUdLBin);
1906 double deltaFL2 = deltaFL * deltaFL;
1907 double weight = value / normalize * L2exp * exp(-deltaFL2 * invFLs2);
1908 hd.zHistogram[lambdaBin][dUdLBin] += weight;
1909 }
1910 }
1911 hd.counts++;
1912 } else {
1913
1914 checkRecursionKernelSize(currentdUdL);
1915 int lambdaBin = indexForLambda(currentLambda);
1916 int dUdLBin = binFordUdL(currentdUdL);
1917 try {
1918 hd.zHistogram[lambdaBin][dUdLBin] += value;
1919 hd.counts++;
1920 } catch (IndexOutOfBoundsException e) {
1921 logger.info(format(" Histogram dimensions %d %d", hd.lambdaBins, hd.dUdLBins));
1922 logger.info(format(
1923 " Count skipped in addToRecursionKernelValue due to an index out of bounds exception.\n L=%10.8f (%d), dU/dL=%10.8f (%d) and count=%10.8f",
1924 currentLambda, lambdaBin, currentdUdL, dUdLBin, value));
1925
1926 }
1927 }
1928 }
1929 }
1930
1931
1932
1933
1934 void allocateRecursionKernel() {
1935
1936 synchronized (this) {
1937 hd.zHistogram = new double[hd.lambdaBins][hd.dUdLBins];
1938 kernelValues = new double[hd.dUdLBins];
1939 }
1940 }
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953 private double integrateNumeric(double[] dUdLs, IntegrationType type) {
1954 double val;
1955 if (hd.discreteLambda) {
1956
1957 double[] lams = Integrate1DNumeric.generateXPoints(0.0, 1.0, hd.lambdaBins, false);
1958 DataSet dSet = new DoublesDataSet(lams, dUdLs, false);
1959 val = Integrate1DNumeric.integrateData(dSet, Integrate1DNumeric.IntegrationSide.LEFT, type);
1960 } else {
1961
1962 double[] midLams = Integrate1DNumeric.generateXPoints(hd.lambdaBinWidth, 1.0 - hd.lambdaBinWidth,
1963 (hd.lambdaBins - 2), false);
1964 double[] midVals = Arrays.copyOfRange(dUdLs, 1, (hd.lambdaBins - 1));
1965 DataSet dSet = new DoublesDataSet(midLams, midVals, false);
1966
1967 val = Integrate1DNumeric.integrateData(dSet, Integrate1DNumeric.IntegrationSide.LEFT, type);
1968
1969
1970
1971 double dL_4 = hd.lambdaBinWidth_2 * 0.5;
1972
1973
1974
1975 double val0 = 0;
1976 double val1 = 0;
1977
1978
1979 if (!lambdaInterface.dEdLZeroAtEnds()) {
1980 double recipSlopeLen = 1.0 / (hd.lambdaBinWidth * 0.75);
1981
1982 double slope = dUdLs[0] - dUdLs[1];
1983 slope *= recipSlopeLen;
1984 val0 = dUdLs[0] + (slope * dL_4);
1985
1986 slope = dUdLs[hd.lambdaBins - 1] - dUdLs[hd.lambdaBins - 2];
1987 slope *= recipSlopeLen;
1988 val1 = dUdLs[hd.lambdaBins - 1] + (slope * dL_4);
1989 logger.fine(format(" Inferred dU/dL values at 0 and 1: %10.5g , %10.5g", val0, val1));
1990 }
1991
1992
1993
1994 val += trapezoid(0, dL_4, val0, dUdLs[0]);
1995 val += trapezoid(dL_4, hd.lambdaBinWidth, dUdLs[0], dUdLs[1]);
1996 val += trapezoid(1.0 - hd.lambdaBinWidth, 1.0 - dL_4, dUdLs[hd.lambdaBins - 2],
1997 dUdLs[hd.lambdaBins - 1]);
1998 val += trapezoid(1.0 - dL_4, 1.0, dUdLs[hd.lambdaBins - 1], val1);
1999 }
2000
2001 return val;
2002 }
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013 private double trapezoid(double x0, double x1, double fx0, double fx1) {
2014 double val = 0.5 * (fx0 + fx1);
2015 val *= (x1 - x0);
2016 return val;
2017 }
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033 private double evaluateKernelForLambda(int lambda, int llFL, int ulFL) {
2034 double maxKernel = Double.MIN_VALUE;
2035
2036 double gaussianBiasMagnitude = hd.biasMag;
2037 if (hd.biasMag <= 0.0) {
2038 gaussianBiasMagnitude = PSEUDO_BIAS_MAGNITUDE;
2039 }
2040
2041 for (int jFL = llFL; jFL <= ulFL; jFL++) {
2042 double value = evaluateKernel(lambda, jFL, gaussianBiasMagnitude);
2043 kernelValues[jFL] = value;
2044 if (value > maxKernel) {
2045 maxKernel = value;
2046 }
2047 }
2048
2049
2050 double offset = 0.0;
2051 if (hd.biasMag > 0.0 && !hd.metaDynamics) {
2052 offset = -maxKernel;
2053 for (int jFL = llFL; jFL <= ulFL; jFL++) {
2054 kernelValues[jFL] += offset;
2055 }
2056 }
2057 return offset;
2058 }
2059
2060
2061
2062
2063
2064
2065
2066 private int lambdaMirror(int bin) {
2067 if (bin < 0) {
2068 return -bin;
2069 }
2070 int lastBin = hd.lambdaBins - 1;
2071 if (bin > lastBin) {
2072
2073 bin -= lastBin;
2074
2075 return lastBin - bin;
2076 }
2077
2078 return bin;
2079 }
2080
2081
2082
2083
2084
2085
2086
2087
2088 private double mirrorFactor(int bin) {
2089 if (hd.discreteLambda) {
2090 return 1.0;
2091 }
2092 if (bin == 0 || bin == hd.lambdaBins - 1) {
2093 return 2.0;
2094 }
2095 return 1.0;
2096 }
2097
2098
2099
2100
2101
2102
2103
2104 private double dUdLforBin(int dUdLBin) {
2105 return hd.dUdLMinimum + dUdLBin * hd.dUdLBinWidth + hd.dUdLBinWidth_2;
2106 }
2107
2108
2109
2110
2111 private double evaluateKernel(int currentLambdaBin, int currentdUdLBin, double gaussianBiasMagnitude) {
2112
2113 double currentLambda = currentLambdaBin * hd.lambdaBinWidth;
2114 double currentdUdL = dUdLforBin(currentdUdLBin);
2115
2116
2117 double invLs2 = 0.5 / hd.lambdaVariance;
2118 double invFLs2 = 0.5 / hd.dUdLVariance;
2119
2120 double sum = 0.0;
2121 int lambdaBiasCutoff = hd.lambdaBiasCutoff;
2122 for (int iL = -lambdaBiasCutoff; iL <= lambdaBiasCutoff; iL++) {
2123 int lambdaBin = currentLambdaBin + iL;
2124 double deltaL = currentLambda - lambdaBin * hd.lambdaBinWidth;
2125 double deltaL2 = deltaL * deltaL;
2126
2127
2128 double L2exp = exp(-deltaL2 * invLs2);
2129
2130
2131 lambdaBin = lambdaMirror(lambdaBin);
2132 double mirrorFactor = mirrorFactor(lambdaBin);
2133
2134 int dUdLbiasCutoff = hd.dUdLBiasCutoff;
2135 for (int jFL = -dUdLbiasCutoff; jFL <= dUdLbiasCutoff; jFL++) {
2136 int dUdLBin = currentdUdLBin + jFL;
2137 double weight = mirrorFactor * getRecursionKernelValue(lambdaBin, dUdLBin);
2138 if (weight <= 0.0) {
2139 continue;
2140 }
2141 double deltaFL = currentdUdL - dUdLforBin(dUdLBin);
2142 double deltaFL2 = deltaFL * deltaFL;
2143 double e = weight * L2exp * exp(-deltaFL2 * invFLs2);
2144 sum += e;
2145 }
2146 }
2147 return gaussianBiasMagnitude * sum;
2148 }
2149
2150
2151
2152
2153
2154
2155
2156
2157 double computeBiasEnergy(double currentLambda, double currentdUdL) {
2158 synchronized (this) {
2159 int currentLambdaBin = indexForLambda(currentLambda);
2160 int currentdUdLBin = binFordUdL(currentdUdL);
2161
2162 double bias1D;
2163 double bias2D = 0.0;
2164
2165 if (!hd.metaDynamics) {
2166 if (hd.biasMag > 0.0) {
2167 int lambdaBiasCutoff = hd.lambdaBiasCutoff;
2168 for (int iL = -lambdaBiasCutoff; iL <= lambdaBiasCutoff; iL++) {
2169
2170 int lambdaBin = currentLambdaBin + iL;
2171 double deltaL = currentLambda - (lambdaBin * hd.lambdaBinWidth);
2172 double deltaL2 = deltaL * deltaL;
2173 double expL2 = exp(-deltaL2 / (2.0 * hd.lambdaVariance));
2174
2175
2176 lambdaBin = lambdaMirror(lambdaBin);
2177 double mirrorFactor = mirrorFactor(lambdaBin);
2178
2179 int dUdLbiasCutoff = hd.dUdLBiasCutoff;
2180 for (int iFL = -dUdLbiasCutoff; iFL <= dUdLbiasCutoff; iFL++) {
2181 int dUdLBin = currentdUdLBin + iFL;
2182
2183 double weight = mirrorFactor * getRecursionKernelValue(lambdaBin, dUdLBin);
2184 if (weight <= 0.0) {
2185 continue;
2186 }
2187
2188 double deltaFL = currentdUdL - dUdLforBin(dUdLBin);
2189 double deltaFL2 = deltaFL * deltaFL;
2190 double bias = weight * hd.biasMag * expL2 * exp(-deltaFL2 / (2.0 * hd.dUdLVariance));
2191 bias2D += bias;
2192 }
2193 }
2194 }
2195
2196 bias1D = energyAndGradient1D(currentLambda, false);
2197 } else {
2198 bias1D = energyAndGradientMeta(currentLambda, false);
2199 }
2200
2201
2202 return bias1D + bias2D;
2203 }
2204 }
2205
2206
2207
2208
2209
2210
2211
2212
2213 double energyAndGradient2D(double currentdUdLambda, double[] chainRule) {
2214 return energyAndGradient2D(ld.lambda, currentdUdLambda, chainRule, hd.biasMag);
2215 }
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226 double energyAndGradient2D(double currentLambda, double currentdUdLambda, double[] chainRule,
2227 double gaussianBiasMagnitude) {
2228
2229 if (gaussianBiasMagnitude <= 0.0) {
2230 chainRule[0] = 0.0;
2231 chainRule[1] = 0.0;
2232 return 0;
2233 }
2234
2235
2236 double gLdEdL = 0.0;
2237 double dGdLambda = 0.0;
2238 double dGdFLambda = 0.0;
2239 int currentLambdaBin = indexForLambda(currentLambda);
2240 int currentdUdLBin = binFordUdL(currentdUdLambda);
2241
2242 int lambdaBiasCutoff = hd.lambdaBiasCutoff;
2243 for (int iL = -lambdaBiasCutoff; iL <= lambdaBiasCutoff; iL++) {
2244 int lambdaBin = currentLambdaBin + iL;
2245
2246
2247 double deltaL = currentLambda - (lambdaBin * hd.lambdaBinWidth);
2248 double deltaL2 = deltaL * deltaL;
2249 double expL2 = exp(-deltaL2 / (2.0 * hd.lambdaVariance));
2250
2251
2252 double mirrorFactor = mirrorFactor(lambdaBin);
2253 int dUdLbiasCutoff = hd.dUdLBiasCutoff;
2254 for (int iFL = -dUdLbiasCutoff; iFL <= dUdLbiasCutoff; iFL++) {
2255 int dUdLBin = currentdUdLBin + iFL;
2256
2257 double weight = mirrorFactor * getRecursionKernelValue(lambdaBin, dUdLBin);
2258 if (weight <= 0.0) {
2259 continue;
2260 }
2261
2262 double deltaFL = currentdUdLambda - dUdLforBin(dUdLBin);
2263 double deltaFL2 = deltaFL * deltaFL;
2264 double bias = weight * gaussianBiasMagnitude * expL2 * exp(-deltaFL2 / (2.0 * hd.dUdLVariance));
2265 gLdEdL += bias;
2266 dGdLambda -= deltaL / hd.lambdaVariance * bias;
2267 dGdFLambda -= deltaFL / hd.dUdLVariance * bias;
2268 }
2269 }
2270
2271 chainRule[0] = dGdLambda;
2272 chainRule[1] = dGdFLambda;
2273 return gLdEdL;
2274 }
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288 private double energyAndGradient1D(boolean gradient) {
2289 return energyAndGradient1D(ld.lambda, gradient);
2290 }
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304 private double energyAndGradient1D(double currentLambda, boolean gradient) {
2305 synchronized (this) {
2306 double biasEnergy = 0.0;
2307 for (int iL0 = 0; iL0 < hd.lambdaBins - 1; iL0++) {
2308 int iL1 = iL0 + 1;
2309
2310
2311 double L0 = iL0 * hd.lambdaBinWidth;
2312 double L1 = L0 + hd.lambdaBinWidth;
2313 double FL0 = ensembleAveragedUdL[iL0];
2314 double FL1 = ensembleAveragedUdL[iL1];
2315 double deltaFL = FL1 - FL0;
2316
2317
2318
2319
2320
2321 boolean done = false;
2322 if (currentLambda <= L1) {
2323 done = true;
2324 L1 = currentLambda;
2325 }
2326
2327
2328 biasEnergy += (FL0 * L1 + deltaFL * L1 * (0.5 * L1 - L0) / hd.lambdaBinWidth);
2329 biasEnergy -= (FL0 * L0 + deltaFL * L0 * (-0.5 * L0) / hd.lambdaBinWidth);
2330 if (done) {
2331
2332 if (gradient) {
2333 dUdLambda -= FL0 + (L1 - L0) * deltaFL / hd.lambdaBinWidth;
2334 }
2335 break;
2336 }
2337 }
2338 return -biasEnergy;
2339 }
2340 }
2341
2342
2343
2344
2345
2346
2347
2348 private double energyAndGradientMeta(boolean gradient) {
2349 return energyAndGradientMeta(ld.lambda, gradient);
2350 }
2351
2352
2353
2354
2355
2356
2357
2358
2359 private double energyAndGradientMeta(double currentLambda, boolean gradient) {
2360
2361 double biasEnergy = 0.0;
2362
2363
2364 int currentBin = indexForLambda(currentLambda);
2365
2366
2367 int lambdaBiasCutoff = hd.lambdaBiasCutoff;
2368 for (int iL = -lambdaBiasCutoff; iL <= lambdaBiasCutoff; iL++) {
2369 int lambdaBin = currentBin + iL;
2370 double deltaL = currentLambda - (lambdaBin * hd.lambdaBinWidth);
2371 double deltaL2 = deltaL * deltaL;
2372
2373 lambdaBin = lambdaMirror(lambdaBin);
2374 double mirrorFactor = mirrorFactor(lambdaBin);
2375 double weight = mirrorFactor * hd.biasMag * countsForLambda(lambdaBin);
2376 if (weight > 0) {
2377 double e = weight * exp(-deltaL2 / (2.0 * hd.lambdaVariance));
2378 biasEnergy += e;
2379
2380 if (gradient) {
2381 dUdLambda -= deltaL / hd.lambdaVariance * e;
2382 }
2383 }
2384 }
2385
2386 return biasEnergy;
2387 }
2388
2389
2390
2391
2392
2393
2394
2395 private double countsForLambda(int lambdaBin) {
2396 synchronized (this) {
2397 double count = 0.0;
2398 for (int i = 0; i < hd.dUdLBins; i++) {
2399 count += hd.zHistogram[lambdaBin][i];
2400 }
2401 return count;
2402 }
2403 }
2404
2405
2406
2407
2408 void checkRecursionKernelSize(double currentdUdL) {
2409
2410 synchronized (this) {
2411 if (currentdUdL > hd.dUdLMaximum) {
2412 logger.info(format(" Current F_lambda %8.2f > maximum histogram size %8.2f.", currentdUdL, hd.dUdLMaximum));
2413
2414 double origDeltaG = updateFreeEnergyDifference(false, false);
2415
2416 int newdUdLBins = hd.dUdLBins;
2417 while (hd.dUdLMinimum + newdUdLBins * hd.dUdLBinWidth < currentdUdL) {
2418 newdUdLBins += 100;
2419 }
2420 double[][] newRecursionKernel = new double[hd.lambdaBins][newdUdLBins];
2421
2422
2423 for (int i = 0; i < hd.lambdaBins; i++) {
2424 arraycopy(hd.zHistogram[i], 0, newRecursionKernel[i], 0, hd.dUdLBins);
2425 }
2426
2427 hd.zHistogram = newRecursionKernel;
2428 hd.dUdLBins = newdUdLBins;
2429 kernelValues = new double[hd.dUdLBins];
2430 hd.dUdLMaximum = hd.dUdLMinimum + hd.dUdLBinWidth * hd.dUdLBins;
2431 logger.info(format(" New histogram %8.2f to %8.2f with %d bins.\n", hd.dUdLMinimum, hd.dUdLMaximum, hd.dUdLBins));
2432
2433 double newFreeEnergy = updateFreeEnergyDifference(true, false);
2434 assert (origDeltaG == newFreeEnergy);
2435 }
2436 if (currentdUdL < hd.dUdLMinimum) {
2437 logger.info(format(" Current F_lambda %8.2f < minimum histogram size %8.2f.", currentdUdL, hd.dUdLMinimum));
2438
2439 double origDeltaG = updateFreeEnergyDifference(false, false);
2440
2441 int offset = 100;
2442 while (currentdUdL < hd.dUdLMinimum - offset * hd.dUdLBinWidth) {
2443 offset += 100;
2444 }
2445 int newdUdLBins = hd.dUdLBins + offset;
2446 double[][] newRecursionKernel = new double[hd.lambdaBins][newdUdLBins];
2447
2448
2449
2450 for (int i = 0; i < hd.lambdaBins; i++) {
2451 arraycopy(hd.zHistogram[i], 0, newRecursionKernel[i], offset, hd.dUdLBins);
2452 }
2453
2454 hd.zHistogram = newRecursionKernel;
2455 hd.dUdLMinimum = hd.dUdLMinimum - offset * hd.dUdLBinWidth;
2456 hd.dUdLBins = newdUdLBins;
2457 kernelValues = new double[hd.dUdLBins];
2458 logger.info(format(" New histogram %8.2f to %8.2f with %d bins.\n", hd.dUdLMinimum, hd.dUdLMaximum, hd.dUdLBins));
2459
2460 double newFreeEnergy = updateFreeEnergyDifference(true, false);
2461 assert (origDeltaG == newFreeEnergy);
2462 }
2463 }
2464 }
2465
2466
2467
2468
2469
2470
2471 void addBias(double dUdL) {
2472
2473 if (hd.asynchronous) {
2474 sendAsynchronous.send(ld.lambda, dUdL, temperingWeight);
2475 } else {
2476 sendSynchronous.send(ld.lambda, dUdL, temperingWeight);
2477 }
2478 }
2479
2480
2481
2482
2483 private void stochasticPreForce() {
2484
2485 double[] thetaPosition = lambdaState.x();
2486 thetaPosition[0] = ld.theta;
2487 stochastic.preForce(OrthogonalSpaceTempering.this);
2488 ld.theta = thetaPosition[0];
2489
2490
2491 if (ld.theta > PI) {
2492 ld.theta -= 2.0 * PI;
2493 } else if (ld.theta <= -PI) {
2494 ld.theta += 2.0 * PI;
2495 }
2496
2497
2498 double sinTheta = sin(ld.theta);
2499 ld.lambda = sinTheta * sinTheta;
2500 lambdaInterface.setLambda(ld.lambda);
2501 }
2502
2503
2504
2505
2506 private void stochasticPostForce() {
2507 double[] thetaPosition = lambdaState.x();
2508 double[] gradient = lambdaState.gradient();
2509
2510 gradient[0] = dUdLambda * sin(2 * ld.theta);
2511 thetaPosition[0] = ld.theta;
2512 stochastic.postForce(gradient);
2513
2514
2515 double[] thetaVelocity = lambdaState.v();
2516 double[] thetaAcceleration = lambdaState.a();
2517 ld.theta = thetaPosition[0];
2518 ld.thetaVelocity = thetaVelocity[0];
2519 ld.thetaAcceleration = thetaAcceleration[0];
2520
2521
2522 if (ld.theta > PI) {
2523 ld.theta -= 2.0 * PI;
2524 } else if (ld.theta <= -PI) {
2525 ld.theta += 2.0 * PI;
2526 }
2527
2528
2529 double sinTheta = sin(ld.theta);
2530 ld.lambda = sinTheta * sinTheta;
2531 lambdaInterface.setLambda(ld.lambda);
2532 }
2533
2534
2535
2536
2537
2538
2539
2540 double getLastReceivedLambda() {
2541 return lastReceivedLambda;
2542 }
2543
2544 public void setLastReceivedLambda(double lastReceivedLambda) {
2545 this.lastReceivedLambda = lastReceivedLambda;
2546 }
2547
2548
2549
2550
2551
2552
2553
2554 double getLastReceivedDUDL() {
2555 return lastReceiveddUdL;
2556 }
2557
2558 void destroy() {
2559 if (sendAsynchronous != null && sendAsynchronous.isAlive()) {
2560 double[] killMessage = new double[]{Double.NaN, Double.NaN, Double.NaN, Double.NaN};
2561 DoubleBuf killBuf = DoubleBuf.buffer(killMessage);
2562 try {
2563 logger.fine(" Sending the termination message.");
2564 world.send(rank, killBuf);
2565 logger.fine(" Termination message was sent successfully.");
2566 logger.fine(format(" Receive thread alive %b status %s", sendAsynchronous.isAlive(),
2567 sendAsynchronous.getState()));
2568 } catch (Exception ex) {
2569 String message = format(" Asynchronous Multiwalker OST termination signal "
2570 + "failed to be sent for process %d.", rank);
2571 logger.log(Level.SEVERE, message, ex);
2572 }
2573 } else {
2574 logger.fine(
2575 " CountReceiveThread was either not initialized, or is not alive. This is the case for the Histogram script.");
2576 }
2577 }
2578
2579 }
2580
2581 }