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 ffx.utilities.FileUtils;
41 import ffx.utilities.HistogramXmlAdapter;
42 import jakarta.xml.bind.JAXBContext;
43 import jakarta.xml.bind.Marshaller;
44 import jakarta.xml.bind.Unmarshaller;
45 import jakarta.xml.bind.annotation.XmlAccessOrder;
46 import jakarta.xml.bind.annotation.XmlAccessType;
47 import jakarta.xml.bind.annotation.XmlAccessorOrder;
48 import jakarta.xml.bind.annotation.XmlAccessorType;
49 import jakarta.xml.bind.annotation.XmlElement;
50 import jakarta.xml.bind.annotation.XmlRootElement;
51 import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
52 import org.apache.commons.configuration2.CompositeConfiguration;
53
54 import javax.annotation.Nullable;
55 import java.io.File;
56 import java.util.logging.Logger;
57
58 import static java.lang.Math.pow;
59 import static java.lang.Math.round;
60 import static java.lang.String.format;
61
62 @XmlRootElement(name = "HistogramData")
63 @XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
64 @XmlAccessorType(XmlAccessType.NONE)
65 public class HistogramData {
66
67 private static final Logger logger = Logger.getLogger(HistogramData.class.getName());
68
69
70
71
72 private static final double DEFAULT_BIAS_MAG = 0.05;
73
74
75
76
77 private static final int DEFAULT_DUDL_BIAS_CUTOFF = 5;
78
79
80
81
82 private static final int DEFAULT_LAMBDA_BIAS_CUTOFF = 5;
83
84
85
86
87 private static final int DEFAULT_COUNT_INTERVAL = 10;
88
89
90
91
92
93
94 private static final double DEFAULT_LAMBDA_BIN_WIDTH = 0.005;
95
96
97
98
99
100
101
102
103 private static final int DEFAULT_LAMBDA_BINS = 201;
104
105
106
107
108 private static final double DEFAULT_DUDL_BIN_WIDTH = 2.0;
109
110
111
112
113 private static final int DEFAULT_DUDL_BINS = 101;
114
115
116
117
118
119
120 private static final double DEFAULT_DUDL_MINIMUM = -DEFAULT_DUDL_BINS;
121
122
123
124
125 private static final boolean DEFAULT_METADYNAMICS = false;
126
127
128
129
130 private static final double DEFAULT_TEMPERING_FACTOR = 2.0;
131
132
133
134
135 private static final double DEFAULT_RESET_HISTOGRAM_AT_LAMBDA = 0.99;
136
137
138
139
140 private static final boolean DEFAULT_RESET_HISTOGRAM = false;
141
142
143
144
145 private final double DEFAULT_BIAS_TO_TEMPERING_OFFSET = 20.0;
146
147
148
149
150 private final boolean DEFAULT_INDEPENDENT_WALKERS = false;
151
152
153
154
155
156
157 private final boolean DEFAULT_INDEPENDENT_WRITE = false;
158
159
160
161
162 private static final boolean DEFAULT_DISCRETE_LAMBDA = false;
163
164
165
166
167 @XmlElement(name = "BiasMag", defaultValue = "" + DEFAULT_BIAS_MAG)
168 double biasMag = DEFAULT_BIAS_MAG;
169
170
171
172
173
174
175
176 @XmlElement(name = "LambdaBiasCutoff", defaultValue = "" + DEFAULT_LAMBDA_BIAS_CUTOFF)
177 int lambdaBiasCutoff = DEFAULT_LAMBDA_BIAS_CUTOFF;
178
179
180
181
182
183 @XmlElement(name = "dUdLBiasCutoff", defaultValue = "" + DEFAULT_DUDL_BIAS_CUTOFF)
184 int dUdLBiasCutoff = DEFAULT_DUDL_BIAS_CUTOFF;
185
186
187
188
189 @XmlElement(name = "CountInterval", defaultValue = "" + DEFAULT_COUNT_INTERVAL)
190 int countInterval = DEFAULT_COUNT_INTERVAL;
191
192
193
194
195
196 @XmlElement(name = "LambdaBinWidth", defaultValue = "" + DEFAULT_LAMBDA_BIN_WIDTH)
197 double lambdaBinWidth = DEFAULT_LAMBDA_BIN_WIDTH;
198
199
200
201
202 @XmlElement(name = "DiscreteLambda", defaultValue = "" + DEFAULT_DISCRETE_LAMBDA)
203 boolean discreteLambda = DEFAULT_DISCRETE_LAMBDA;
204
205
206
207
208 @XmlElement(name = "dUdLBinWidth", defaultValue = "" + DEFAULT_DUDL_BIN_WIDTH)
209 double dUdLBinWidth = DEFAULT_DUDL_BIN_WIDTH;
210
211
212
213
214
215
216 @XmlElement(name = "dUdLMinimum", defaultValue = "" + DEFAULT_DUDL_MINIMUM)
217 double dUdLMinimum = DEFAULT_DUDL_MINIMUM;
218
219
220
221
222 @XmlElement(name = "MetaDynamics", defaultValue = "" + DEFAULT_METADYNAMICS)
223 boolean metaDynamics = DEFAULT_METADYNAMICS;
224
225
226
227
228
229 @XmlElement(name = "TemperingFactor", defaultValue = "" + DEFAULT_TEMPERING_FACTOR)
230 double temperingFactor = DEFAULT_TEMPERING_FACTOR;
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246 @XmlElement(name = "TemperingOffset", defaultValue = "-1.0")
247 private double temperingOffset = -1.0;
248
249
250
251
252 @XmlElement(name = "ResetHistogramAtLambda", defaultValue = "" + DEFAULT_RESET_HISTOGRAM_AT_LAMBDA)
253 double resetHistogramAtLambda = DEFAULT_RESET_HISTOGRAM_AT_LAMBDA;
254
255
256
257
258 @XmlElement(name = "ResetHistogram", defaultValue = "" + DEFAULT_RESET_HISTOGRAM)
259 boolean resetHistogram = DEFAULT_RESET_HISTOGRAM;
260
261 @XmlElement(name = "IndependentWalkers", defaultValue = "" + DEFAULT_INDEPENDENT_WALKERS)
262 boolean independentWalkers = DEFAULT_INDEPENDENT_WALKERS;
263
264 @XmlElement(name = "IndependentWrite", defaultValue = "" + DEFAULT_INDEPENDENT_WRITE)
265 boolean independentWrite = DEFAULT_INDEPENDENT_WRITE;
266
267
268
269
270
271
272 @XmlElement(name = "Asynchronous", defaultValue = "" + true)
273 boolean asynchronous = true;
274
275
276
277
278
279
280
281
282
283
284 @XmlElement(name = "dUdLBins", defaultValue = "" + DEFAULT_DUDL_BINS)
285 public int dUdLBins = DEFAULT_DUDL_BINS;
286
287
288
289
290 @XmlElement(name = "Counts", defaultValue = "0")
291 public int counts = 0;
292
293
294
295
296
297 @XmlElement(name = "Data", required = true)
298 @XmlJavaTypeAdapter(HistogramXmlAdapter.class)
299 double[][] zHistogram = new double[DEFAULT_LAMBDA_BINS][DEFAULT_DUDL_BINS];
300
301
302
303
304 private File histogramFile = null;
305
306
307
308
309 private String histogramFileName = null;
310
311
312
313
314 private boolean histogramRead = false;
315
316
317
318
319
320
321
322
323
324
325
326 public int lambdaBins = DEFAULT_LAMBDA_BINS;
327
328
329
330
331 public double lambdaBinWidth_2 = DEFAULT_LAMBDA_BIN_WIDTH / 2.0;
332
333
334
335
336
337
338
339
340 public double minLambda = -DEFAULT_LAMBDA_BIN_WIDTH / 2.0;
341
342
343
344
345 public double[] lambdaLadder = null;
346
347
348
349
350
351 public double lambdaVariance = pow(2.0 * DEFAULT_LAMBDA_BIN_WIDTH, 2);
352
353
354
355
356
357
358
359
360
361 public double dUdLMaximum = DEFAULT_DUDL_BINS;
362
363
364
365
366 public double dUdLBinWidth_2 = DEFAULT_DUDL_BIN_WIDTH / 2.0;
367
368
369
370
371
372 public double dUdLVariance = pow(2.0 * dUdLBinWidth, 2);
373
374
375
376
377
378
379
380 public static void writeHistogram(HistogramData histogramData, File file) {
381 try {
382 JAXBContext jaxbContext = JAXBContext.newInstance(HistogramData.class);
383 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
384 jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
385 jaxbMarshaller.marshal(histogramData, file);
386 } catch (Exception e) {
387 logger.warning(" Exception writing histogram:\n " + e);
388 }
389 }
390
391
392
393
394
395
396
397 public static HistogramData readHistogram(@Nullable File file) {
398 if (file != null && file.exists() && file.canRead()) {
399 try {
400 JAXBContext jaxbContext = JAXBContext.newInstance(HistogramData.class);
401 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
402 HistogramData histogramData = (HistogramData) unmarshaller.unmarshal(file);
403 histogramData.setHistogramFile(file);
404 histogramData.setHistogramRead(true);
405 histogramData.rectify();
406 return histogramData;
407 } catch (Exception e) {
408 logger.warning(" Exception reading histogram:\n " + e);
409 }
410 }
411 HistogramData histogramData = new HistogramData();
412 histogramData.setHistogramFile(file);
413 histogramData.rectify();
414 return histogramData;
415 }
416
417 private void rectify() {
418
419 int hisLambdaBins = zHistogram.length;
420 if (lambdaBins != hisLambdaBins) {
421 logger.fine(" Current LambdaBins: " + lambdaBins);
422 logger.fine(" Updated to: " + hisLambdaBins);
423 lambdaBins = hisLambdaBins;
424 lambdaBinWidth = 1.0 / (lambdaBins - 1);
425 }
426 int hisDUDLBins = zHistogram[0].length;
427 if (dUdLBins != hisDUDLBins) {
428 logger.fine(" Current dUdLBins: " + dUdLBins);
429 logger.fine(" Updated to: " + hisDUDLBins);
430 dUdLBins = hisDUDLBins;
431 }
432 rectifyLambdaVariables();
433 rectifyDUDLVariables();
434 }
435
436
437
438
439 private void rectifyDUDLVariables() {
440
441 dUdLBinWidth_2 = dUdLBinWidth / 2.0;
442 dUdLMaximum = dUdLMinimum + (dUdLBins * dUdLBinWidth);
443 dUdLVariance = pow(2.0 * dUdLBinWidth, 2);
444 }
445
446
447
448
449 private void rectifyLambdaVariables() {
450
451 int n = (int) round(1.0 / lambdaBinWidth);
452
453 lambdaBinWidth = 1.0 / n;
454
455 lambdaBins = n + 1;
456 if (discreteLambda) {
457 lambdaLadder = new double[lambdaBins];
458 lambdaLadder[0] = 0.0;
459 lambdaLadder[lambdaBins - 1] = 1.0;
460 for (int i = 1; i < lambdaBins - 1; i++) {
461 lambdaLadder[i] = lambdaBinWidth * i;
462 }
463 lambdaBinWidth_2 = 0.0;
464 minLambda = 0.0;
465 lambdaBiasCutoff = 0;
466 } else {
467 lambdaLadder = null;
468 lambdaBinWidth_2 = lambdaBinWidth / 2.0;
469 minLambda = -lambdaBinWidth_2;
470
471 if (lambdaBiasCutoff == 0) {
472
473 lambdaBiasCutoff = DEFAULT_LAMBDA_BIAS_CUTOFF;
474 }
475 }
476 lambdaVariance = pow(2.0 * lambdaBinWidth, 2);
477 }
478
479 public void setCountInterval(int countInterval) {
480 this.countInterval = countInterval;
481 }
482
483
484
485
486 public void writeHistogram() {
487 writeHistogram(this, histogramFile);
488 }
489
490 public String getHistogramFileName() {
491 return histogramFileName;
492 }
493
494 public File getHistogramFile() {
495 return histogramFile;
496 }
497
498 public void setHistogramFile(@Nullable File histogramFile) {
499 this.histogramFile = histogramFile;
500 if (histogramFile != null) {
501 histogramFileName = FileUtils.relativePathTo(histogramFile).toString();
502 }
503 }
504
505 public boolean wasHistogramRead() {
506 return histogramRead;
507 }
508
509 public void setHistogramRead(boolean histogramRead) {
510 this.histogramRead = histogramRead;
511 }
512
513
514
515
516
517
518 public void setIndependentWalkers(boolean independentWalkers) {
519 this.independentWalkers = independentWalkers;
520 if (independentWalkers) {
521 setWriteIndependent(true);
522 }
523 }
524
525
526
527
528
529
530
531 public void setWriteIndependent(boolean independentWrite) throws IllegalArgumentException {
532 if (!independentWrite && independentWalkers) {
533 throw new IllegalArgumentException(" Independent walkers implies independent writing.");
534 }
535 this.independentWrite = independentWrite;
536 }
537
538
539
540
541
542
543 public boolean independentWrite() {
544 return independentWrite;
545 }
546
547
548
549
550
551
552 public double getBiasMag() {
553 return biasMag;
554 }
555
556
557
558
559
560
561
562 public void setBiasMag(double biasMag) {
563 this.biasMag = biasMag;
564 }
565
566 public void setTemperingFactor(double temperingFactor) {
567 this.temperingFactor = temperingFactor;
568 }
569
570 public void setMetaDynamics(boolean metaDynamics) {
571 this.metaDynamics = metaDynamics;
572 }
573
574 public double getLambdaBinWidth() {
575 return lambdaBinWidth;
576 }
577
578 public int getLambdaBins() {
579 return lambdaBins;
580 }
581
582 public int getDUDLBins() {
583 return dUdLBins;
584 }
585
586
587
588
589
590
591 public void setLambdaBinWidth(double lambdaBinWidth) {
592 if (lambdaBinWidth <= 0.0 || lambdaBinWidth > 1.0) {
593 this.lambdaBinWidth = DEFAULT_LAMBDA_BIN_WIDTH;
594 } else {
595 this.lambdaBinWidth = lambdaBinWidth;
596 }
597 rectifyLambdaVariables();
598 }
599
600 public void setdUdLBinWidth(double dUdLBinWidth) {
601
602 double ratio = dUdLBinWidth / this.dUdLBinWidth;
603 this.dUdLMinimum *= ratio;
604 this.dUdLBinWidth = dUdLBinWidth;
605 rectifyDUDLVariables();
606 }
607
608
609
610
611
612
613 public double getTemperingOffset() {
614 if (temperingOffset >= 0.0) {
615 return temperingOffset;
616 }
617 return biasMag * DEFAULT_BIAS_TO_TEMPERING_OFFSET;
618 }
619
620
621
622
623
624
625 public void setTemperingOffset(double temperingOffset) {
626 this.temperingOffset = temperingOffset;
627 }
628
629 public void setAsynchronous(boolean asynchronous) {
630 this.asynchronous = asynchronous;
631 }
632
633 public double resetHistogramAtLambda() {
634 return resetHistogramAtLambda;
635 }
636
637
638
639
640
641
642 public void setResetHistogramAtLambda(double resetHistogramAtLambda) {
643 if (resetHistogramAtLambda < 0.0 || resetHistogramAtLambda > 1.0) {
644 this.resetHistogramAtLambda = DEFAULT_RESET_HISTOGRAM_AT_LAMBDA;
645 this.resetHistogram = false;
646 } else {
647 this.resetHistogramAtLambda = resetHistogramAtLambda;
648 this.resetHistogram = true;
649 }
650 }
651
652 public void setDiscreteLambda(boolean discreteLambda) {
653 this.discreteLambda = discreteLambda;
654 rectifyLambdaVariables();
655 }
656
657 public void applyProperties(CompositeConfiguration properties) {
658 if (properties.containsKey("lambda-bias-cutoff")) {
659 lambdaBiasCutoff = properties.getInt("lambda-bias-cutoff");
660 }
661 if (properties.containsKey("dudl-bias-cutoff")) {
662 dUdLBiasCutoff = properties.getInt("dudl-bias-cutoff");
663 }
664 if (properties.containsKey("ost-bias-mag")) {
665 double bias = properties.getDouble("ost-bias-mag");
666 setBiasMag(bias);
667 }
668 if (properties.containsKey("ost-temperOffset")) {
669 double offset = properties.getDouble("ost-temperOffset");
670 setTemperingOffset(offset);
671 }
672 if (properties.containsKey("lambda-bin-width")) {
673 double width = properties.getDouble("lambda-bin-width");
674 setLambdaBinWidth(width);
675 }
676 if (properties.containsKey("flambda-bin-width")) {
677 double dUdLBinWidth = properties.getDouble("flambda-bin-width");
678 setdUdLBinWidth(dUdLBinWidth);
679 }
680 if (properties.containsKey("discrete-lambda")) {
681 boolean discreteLambda = properties.getBoolean("discrete-lambda");
682 setDiscreteLambda(discreteLambda);
683 }
684 }
685
686 public String toString() {
687 return format(" Lambda bins: %6d\n", lambdaBins)
688 + format(" Lambda bin width: %6.3f\n", lambdaBinWidth)
689 + format(" dU/dL bins: %6d\n", dUdLBins)
690 + format(" dU/dL bin width: %6.3f (kcal/mol)\n", dUdLBinWidth)
691 + format(" Bias magnitude: %6.3f (kcal/mol)\n", biasMag)
692 + format(" Tempering offset: %6.3f (kcal/mol)\n", getTemperingOffset())
693 + format(" Tempering rate: %6.3f\n", temperingFactor)
694 + format(" Discrete lambda: %6B\n", discreteLambda)
695 + format(" Meta-dynamics: %6B\n\n", metaDynamics);
696 }
697
698 }