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 static ffx.utilities.Constants.KCAL_TO_GRAM_ANG2_PER_PS2;
41 import static ffx.utilities.Constants.kB;
42 import static org.apache.commons.math3.util.FastMath.exp;
43
44 import edu.rit.mp.DoubleBuf;
45 import edu.rit.pj.Comm;
46 import ffx.algorithms.AlgorithmListener;
47 import ffx.algorithms.Terminatable;
48 import java.io.IOException;
49 import java.util.Random;
50 import java.util.logging.Level;
51 import java.util.logging.Logger;
52
53
54
55
56
57
58
59 public class ReplicaExchange implements Terminatable {
60
61 private static final Logger logger = Logger.getLogger(ReplicaExchange.class.getName());
62 private final int nReplicas;
63 private final Random random;
64
65 private final Comm world;
66
67 private final int rank;
68
69
70
71
72 private final double[][] parameters;
73
74
75
76
77 private final DoubleBuf[] parametersBuf;
78 private final MolecularDynamics replica;
79 private boolean done = false;
80 private boolean terminate = false;
81 private final double[] myParameters;
82 private final DoubleBuf myParametersBuf;
83 private final int[] temp2Rank;
84 private final int[] rank2Temp;
85 private double[] temperatures;
86 private final int[] tempAcceptedCount;
87 private final int[] rankAcceptedCount;
88 private final int[] tempTrialCount;
89 boolean monteCarlo;
90
91
92
93
94
95
96
97
98
99 public ReplicaExchange(MolecularDynamics molecularDynamics, AlgorithmListener listener,
100 double temperature, double exponent, boolean monteCarlo) {
101
102 this.replica = molecularDynamics;
103 this.monteCarlo = monteCarlo;
104
105
106
107
108
109
110 world = Comm.world();
111
112
113 int numProc = world.size();
114 rank = world.rank();
115
116 nReplicas = numProc;
117 temperatures = new double[nReplicas];
118 temp2Rank = new int[nReplicas];
119 rank2Temp = new int[nReplicas];
120 tempAcceptedCount = new int[nReplicas];
121 rankAcceptedCount = new int[nReplicas];
122 tempTrialCount = new int[nReplicas];
123
124 setExponentialTemperatureLadder(temperature, exponent);
125
126 random = new Random();
127 random.setSeed(0);
128
129
130 parameters = new double[nReplicas][2];
131 parametersBuf = new DoubleBuf[nReplicas];
132 for (int i = 0; i < nReplicas; i++) {
133 parametersBuf[i] = DoubleBuf.buffer(parameters[i]);
134 }
135
136
137
138 myParameters = parameters[rank];
139 myParametersBuf = parametersBuf[rank];
140 }
141
142
143
144
145
146
147
148
149
150
151 public void sample(int cycles, long nSteps, double timeStep, double printInterval,
152 double saveInterval) {
153 done = false;
154 terminate = false;
155 for (int i = 0; i < cycles; i++) {
156
157 if (terminate) {
158 done = true;
159 break;
160 }
161 dynamic(nSteps, timeStep, printInterval, saveInterval);
162 logger.info(String.format(" Applying exchange condition for cycle %d.", i));
163 exchange(i);
164 }
165 }
166
167
168
169
170
171
172
173 public void setExponentialTemperatureLadder(double lowTemperature, double exponent) {
174 for (int i = 0; i < nReplicas; i++) {
175 temperatures[i] = lowTemperature * exp(exponent * i);
176 temp2Rank[i] = i;
177 rank2Temp[i] = i;
178 }
179 }
180
181
182
183
184
185
186 public void setTemperatures(double[] temperatures) {
187 assert (temperatures.length == nReplicas);
188 this.temperatures = temperatures;
189 }
190
191
192
193
194
195
196
197
198 @Override
199 public void terminate() {
200 terminate = true;
201 while (!done) {
202 synchronized (this) {
203 try {
204 wait(1);
205 } catch (InterruptedException e) {
206 logger.log(Level.WARNING, "Exception terminating replica exchange.\n", e);
207 }
208 }
209 }
210 }
211
212
213
214
215
216
217 private void exchange(int cycle) {
218 int start;
219 int increment;
220 if (monteCarlo) {
221
222 start = cycle % 2;
223 increment = 2;
224 } else {
225
226 start = 0;
227 increment = 1;
228 }
229
230 for (int temperature = start; temperature < nReplicas - 1; temperature += increment) {
231
232
233 int rankA = temp2Rank[temperature];
234 int rankB = temp2Rank[temperature + 1];
235
236
237 double tempA = parameters[rankA][0];
238 double tempB = parameters[rankB][0];
239 double betaA = KCAL_TO_GRAM_ANG2_PER_PS2 / (tempA * kB);
240 double betaB = KCAL_TO_GRAM_ANG2_PER_PS2 / (tempB * kB);
241 double energyA = parameters[rankA][1];
242 double energyB = parameters[rankB][1];
243
244
245 double deltaE = (energyA - energyB) * (betaB - betaA);
246
247
248
249 tempTrialCount[temperature]++;
250 if (deltaE < 0.0 || random.nextDouble() < exp(-deltaE)) {
251 tempAcceptedCount[temperature]++;
252 double tempAcceptance =
253 tempAcceptedCount[temperature] * 100.0 / (tempTrialCount[temperature]);
254
255 double rankAcceptance;
256 if (tempA < tempB) {
257 rankAcceptedCount[rankA]++;
258 rankAcceptance = rankAcceptedCount[rankA] * 100.0 / (tempTrialCount[temperature]);
259 } else {
260 rankAcceptedCount[rankB]++;
261 rankAcceptance = rankAcceptedCount[rankB] * 100.0 / (tempTrialCount[temperature + 1]);
262 }
263
264
265 parameters[rankA][0] = tempB;
266 parameters[rankB][0] = tempA;
267
268 parameters[rankA][1] = energyB;
269 parameters[rankB][1] = energyA;
270
271
272 temp2Rank[temperature] = rankB;
273 temp2Rank[temperature + 1] = rankA;
274
275
276 rank2Temp[rankA] = temperature + 1;
277 rank2Temp[rankB] = temperature;
278
279 logger.info(String.format(
280 " RepEx accepted (%5.1f%%) (%5.1f%%) for %6.2f (%d) and %6.2f (%d) for dE=%10.4f.",
281 tempAcceptance, rankAcceptance, tempA, rankA, tempB, rankB, deltaE));
282 } else {
283 double tempAcceptance =
284 tempAcceptedCount[temperature] * 100.0 / (tempTrialCount[temperature]);
285 double rankAcceptance =
286 rankAcceptedCount[temperature] * 100.0 / (tempTrialCount[temperature]);
287 logger.info(String.format(
288 " RepEx rejected (%5.1f%%) (f%5.1f%%) for %6.2f (%d) and %6.2f (%d) for dE=%10.4f.",
289 tempAcceptance, rankAcceptance, tempA, rankA, tempB, rankB, deltaE));
290 }
291 }
292 }
293
294
295
296
297
298
299
300
301
302
303 private void dynamic(final long nSteps, final double timeStep, final double printInterval,
304 final double saveInterval) {
305
306 int i = rank2Temp[rank];
307
308
309 boolean initVelocities = true;
310 replica.dynamic(nSteps, timeStep, printInterval, saveInterval, temperatures[i], initVelocities,
311 null);
312
313
314 myParameters[0] = temperatures[i];
315 myParameters[1] = replica.state.getPotentialEnergy();
316
317
318 try {
319 world.allGather(myParametersBuf, parametersBuf);
320 } catch (IOException ex) {
321 String message = " Replica Exchange allGather failed.";
322 logger.log(Level.SEVERE, message, ex);
323 }
324 }
325 }