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.mc;
39
40 import static ffx.utilities.Constants.R;
41 import static java.lang.Double.isFinite;
42 import static java.lang.String.format;
43 import static org.apache.commons.math3.util.FastMath.exp;
44 import static org.apache.commons.math3.util.FastMath.min;
45
46 import java.util.ArrayList;
47 import java.util.List;
48 import java.util.Random;
49 import java.util.logging.Logger;
50
51
52
53
54
55
56
57
58 public abstract class BoltzmannMC implements MetropolisMC {
59
60
61 private static final Logger logger = Logger.getLogger(BoltzmannMC.class.getName());
62
63 protected final Random random = new Random();
64
65
66
67 private double temperature = 298.15;
68
69
70
71 private double invKBT = 1.0 / (R * temperature);
72
73 private boolean print = true;
74 private double e1 = 0.0;
75 private double e2 = 0.0;
76 private double lastE = 0.0;
77 private boolean lastAccept = false;
78
79
80
81
82
83
84
85
86
87 public static double acceptChance(double invKT, double e1, double e2) {
88 double dE = e2 - e1;
89 return min(exp(-invKT * dE), 1.0);
90 }
91
92
93
94
95
96
97
98
99
100
101 public static boolean evaluateMove(Random random, double invKT, double e1, double e2) {
102 boolean e1Finite = isFinite(e1);
103 boolean e2Finite = isFinite(e2);
104 if (!e1Finite && !e2Finite) {
105 throw new IllegalArgumentException(
106 format(" Attempting to evaluate " + "move with non-finite energies %f and %f!", e1, e2));
107 } else if (!e1Finite) {
108 throw new IllegalArgumentException(
109 format(" Attempting to evaluate move " + "from non-finite %f to finite %.4f!", e1, e2));
110 } else if (!e2Finite) {
111 throw new IllegalArgumentException(
112 format(" Attempting to evaluate move " + "from finite %.4f to non-finite %.4f!", e1, e2));
113 }
114 if (e2 <= e1) {
115 return true;
116 } else {
117
118 double prob = acceptChance(invKT, e1, e2);
119 assert (prob >= 0.0
120 && prob <= 1.0) : "The probability of an MC move up in energy should be between [0 ..1].";
121 double trial = random.nextDouble();
122 return (trial <= prob);
123 }
124 }
125
126
127
128
129
130
131 @Override
132 public boolean evaluateMove(double e1, double e2) {
133 return evaluateMove(random, invKBT, e1, e2);
134 }
135
136
137 @Override
138 public boolean getAccept() {
139 return lastAccept;
140 }
141
142
143 @Override
144 public double getE1() {
145 return e1;
146 }
147
148
149 @Override
150 public double getE2() {
151 return e2;
152 }
153
154
155 @Override
156 public double getTemperature() {
157 return temperature;
158 }
159
160
161 @Override
162 public void setTemperature(double temp) {
163 temperature = temp;
164 invKBT = 1.0 / (R * temperature);
165 }
166
167
168 @Override
169 public double lastEnergy() {
170 return lastE;
171 }
172
173
174 @Override
175 public boolean mcStep(MCMove move) {
176 return mcStep(move, currentEnergy());
177 }
178
179
180 @Override
181 public boolean mcStep(MCMove move, double en1) {
182 List<MCMove> moveList = new ArrayList<>(1);
183 moveList.add(move);
184 return mcStep(moveList, en1);
185 }
186
187
188 @Override
189 public boolean mcStep(List<MCMove> moves) {
190 return mcStep(moves, currentEnergy());
191 }
192
193
194
195
196
197
198
199
200 @Override
201 public boolean mcStep(List<MCMove> moves, double en1) {
202 storeState();
203 e1 = en1;
204
205 int nMoves = moves.size();
206 for (MCMove move : moves) {
207 move.move();
208 }
209
210 lastE = currentEnergy();
211 e2 = lastE;
212 if (evaluateMove(e1, e2)) {
213 lastAccept = true;
214 if (print) {
215 logger.info(format(" Monte Carlo step accepted: e1 -> e2 %10.6f -> %10.6f", e1, e2));
216 }
217 return true;
218 } else {
219 lastAccept = false;
220 for (int i = nMoves - 1; i >= 0; i--) {
221 moves.get(i).revertMove();
222 }
223 lastE = e1;
224 if (print) {
225 logger.info(format(" Monte Carlo step rejected: e1 -> e2 %10.6f -> %10.6f", e1, e2));
226 }
227 return false;
228 }
229 }
230
231
232 @Override
233 public void setPrint(boolean print) {
234 this.print = print;
235 }
236
237
238
239
240
241
242 protected void setRandomSeed(int randomSeed) {
243 random.setSeed(randomSeed);
244 }
245
246
247
248
249
250
251 protected abstract double currentEnergy();
252
253
254
255
256
257
258 protected abstract void storeState();
259 }