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.numerics.estimator;
39
40 import static ffx.numerics.estimator.EstimateBootstrapper.getBootstrapIndices;
41 import static java.util.Arrays.copyOf;
42 import static org.apache.commons.math3.util.FastMath.exp;
43 import static org.apache.commons.math3.util.FastMath.log;
44
45 import ffx.utilities.Constants;
46
47 import java.util.Random;
48 import java.util.logging.Level;
49 import java.util.logging.Logger;
50 import java.util.stream.IntStream;
51
52
53
54
55
56
57
58
59
60 public class Zwanzig extends SequentialEstimator implements BootstrappableEstimator {
61
62 private static final Logger logger = Logger.getLogger(SequentialEstimator.class.getName());
63 public final Directionality directionality;
64 private final boolean forwards;
65
66
67
68 private final int nWindows;
69
70
71
72 private final double[] windowFreeEnergyDifferences;
73 private final double[] windowEnthalpies;
74
75
76
77 private final double[] windowFreeEnergyUncertainties;
78 private final Random random;
79
80
81
82 private double totalFreeEnergyDifference;
83
84
85
86
87 private double totalFreeEnergyUncertainty;
88
89
90
91
92 private double totalEnthalpy;
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public Zwanzig(double[] lambdaValues, double[][] energiesLow, double[][] energiesAt,
115 double[][] energiesHigh,
116 double[] temperature, Directionality directionality) {
117 super(lambdaValues, energiesLow, energiesAt, energiesHigh, temperature);
118 this.directionality = directionality;
119 nWindows = nTrajectories - 1;
120
121 windowFreeEnergyDifferences = new double[nWindows];
122 windowFreeEnergyUncertainties = new double[nWindows];
123 windowEnthalpies = new double[nWindows];
124
125 forwards = directionality.equals(Directionality.FORWARDS);
126 random = new Random();
127
128 estimateDG();
129 }
130
131
132
133
134 @Override
135 public Zwanzig copyEstimator() {
136 return new Zwanzig(lamValues, eLow, eAt, eHigh, temperatures, directionality);
137 }
138
139
140
141
142 @Override
143 public final void estimateDG(final boolean randomSamples) {
144 double cumDG = 0;
145
146 Level warningLevel = randomSamples ? Level.FINE : Level.WARNING;
147
148 for (int i = 0; i < nWindows; i++) {
149 int windowIndex = forwards ? 0 : 1;
150 windowIndex += i;
151 double[] e1 = eAt[windowIndex];
152 double[] e2 = forwards ? eHigh[windowIndex] : eLow[windowIndex];
153 double sign = forwards ? 1.0 : -1.0;
154 double beta = -temperatures[windowIndex] * Constants.R;
155 double invBeta = 1.0 / beta;
156
157 int len = e1.length;
158 if (len == 0) {
159 logger.log(warningLevel, " Skipping frame " + i + " due to lack of snapshots!");
160 continue;
161 }
162
163
164 int[] samples =
165 randomSamples ? getBootstrapIndices(len, random) : IntStream.range(0, len).toArray();
166
167 double sum = 0.0;
168 double num = 0.0;
169 double uAve = 0.0;
170 for (int indJ = 0; indJ < len; indJ++) {
171 int j = samples[indJ];
172 double dE = e2[j] - e1[j];
173 if (sign > 0) {
174 uAve += e1[j];
175 var term = exp(invBeta * dE);
176 sum += term;
177 num += e2[j] * term;
178 } else {
179 uAve += e2[j];
180 var term = exp(invBeta * dE);
181 sum += term;
182 num += e1[j] * term;
183 }
184 }
185
186 uAve = uAve / len;
187
188 double dG = sign * beta * log(sum / len);
189 windowFreeEnergyDifferences[i] = dG;
190 windowEnthalpies[i] = sign * ((num / sum) - uAve);
191 windowFreeEnergyUncertainties[i] = 0.0;
192 totalEnthalpy += windowEnthalpies[i];
193 cumDG += dG;
194 }
195
196 totalFreeEnergyDifference = cumDG;
197 totalFreeEnergyUncertainty = 0.0;
198 }
199
200
201
202
203 @Override
204 public final void estimateDG() {
205 estimateDG(false);
206 }
207
208
209
210
211 @Override
212 public double[] getBinEnergies() {
213 return copyOf(windowFreeEnergyDifferences, nWindows);
214 }
215
216
217
218
219 @Override
220 public double[] getBinUncertainties() {
221 return copyOf(windowFreeEnergyUncertainties, nWindows);
222 }
223
224
225
226
227 @Override
228 public double getFreeEnergy() {
229 return totalFreeEnergyDifference;
230 }
231
232
233
234
235 @Override
236 public double getUncertainty() {
237 return totalFreeEnergyUncertainty;
238 }
239
240
241
242
243 @Override
244 public int numberOfBins() {
245 return nWindows;
246 }
247
248
249
250
251 @Override
252 public double[] getBinEnthalpies() {
253 return copyOf(windowEnthalpies, nWindows);
254 }
255
256
257
258
259
260 public enum Directionality {
261 FORWARDS,
262 BACKWARDS
263 }
264 }