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