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.cli;
39
40 import ffx.algorithms.AlgorithmListener;
41 import ffx.algorithms.optimize.anneal.AnnealingSchedule;
42 import ffx.algorithms.optimize.anneal.FlatEndAnnealSchedule;
43 import ffx.algorithms.optimize.anneal.SimulatedAnnealing;
44 import ffx.numerics.Potential;
45 import ffx.potential.MolecularAssembly;
46 import picocli.CommandLine.ArgGroup;
47 import picocli.CommandLine.Option;
48
49 import java.io.File;
50 import java.util.logging.Logger;
51
52 import static java.lang.String.format;
53
54
55
56
57
58
59
60
61 public class AnnealOptions {
62
63 private static final Logger logger = Logger.getLogger(AnnealOptions.class.getName());
64
65
66
67
68 @ArgGroup(heading = "%n Simulated Annealing Options%n", validate = false)
69 private final AnnealOptionGroup group = new AnnealOptionGroup();
70
71
72
73
74
75
76 public int getWindows() {
77 return group.windows;
78 }
79
80
81
82
83
84
85
86
87
88
89 public SimulatedAnnealing createAnnealer(DynamicsOptions dynamicsOptions,
90 MolecularAssembly molecularAssembly, Potential potential,
91 AlgorithmListener algorithmListener) {
92 return createAnnealer(dynamicsOptions, molecularAssembly, potential, algorithmListener, null);
93 }
94
95
96
97
98
99
100
101
102
103
104
105 public SimulatedAnnealing createAnnealer(DynamicsOptions dynamicsOptions, MolecularAssembly molecularAssembly,
106 Potential potential, AlgorithmListener algorithmListener,
107 File dynFile) {
108 AnnealingSchedule schedule = getSchedule();
109 double totNormLen = schedule.totalWindowLength();
110 long totSteps = dynamicsOptions.getSteps();
111 long perWindowSteps = (long) (totSteps / totNormLen);
112
113 if (totSteps > perWindowSteps * totNormLen) {
114 ++perWindowSteps;
115 }
116
117 long minWindowSteps = (long) (perWindowSteps * schedule.minWindowLength());
118 long maxWindowSteps = (long) (perWindowSteps * schedule.maxWindowLength());
119 int nWindows = schedule.getNumWindows();
120
121 if (minWindowSteps == maxWindowSteps && minWindowSteps == perWindowSteps) {
122 logger.info(format(" Each of %d simulated annealing windows will have %d steps each, for a "
123 + "total duration of %d time-steps", nWindows, perWindowSteps, perWindowSteps * nWindows));
124 } else {
125 logger.info(format(" Each of %d simulated annealing windows will have %d-%d steps each, "
126 + "with a \"normal\" length of %d steps, for a total duration of %d time-steps", nWindows,
127 minWindowSteps, maxWindowSteps, perWindowSteps,
128 (int) (perWindowSteps * schedule.totalWindowLength())));
129 }
130
131 if (nWindows < 201) {
132 StringBuilder sb = new StringBuilder(
133 "\n Simulated annealing windows [index,MD steps, temperature (K)]:\n [");
134 for (int i = 0; i < nWindows; i++) {
135 double len = schedule.windowLength(i);
136 double temp = schedule.getTemperature(i);
137 sb.append(format("[%d,%d,%10.4g]", (i + 1), (int) (len * perWindowSteps), temp));
138 if (i == nWindows - 1) {
139 sb.append("]\n");
140 } else if (i % 10 == 9) {
141 sb.append("\n");
142 } else {
143 sb.append(",");
144 }
145 }
146 logger.info(sb.toString());
147 } else {
148 logger.info(" Skipping printout of window lengths/temperatures (max printout at 200 windows)");
149 }
150
151 return new SimulatedAnnealing(molecularAssembly, potential, algorithmListener,
152 dynamicsOptions.thermostat, dynamicsOptions.integrator, schedule, perWindowSteps,
153 dynamicsOptions.getDt(), isReinitVelocities(), dynFile);
154 }
155
156
157
158
159
160
161 public AnnealingSchedule getSchedule() {
162 SimulatedAnnealing.Schedules schedules = SimulatedAnnealing.Schedules.parse(getTemperString());
163 AnnealingSchedule annealingSchedule = schedules.generate(getWindows(), getLow(), getUpper());
164 if (getTemperBefore() > 0 || getTemperAfter() > 0) {
165 annealingSchedule = new FlatEndAnnealSchedule(annealingSchedule, getLow(), getUpper(),
166 getTemperBefore(), getTemperAfter());
167 }
168 return annealingSchedule;
169 }
170
171 public void setWindows(int windows) {
172 group.windows = windows;
173 }
174
175
176
177
178
179
180 public double getLow() {
181 return group.low;
182 }
183
184 public void setLow(double low) {
185 group.low = low;
186 }
187
188
189
190
191
192
193 public double getUpper() {
194 return group.upper;
195 }
196
197 public void setUpper(double upper) {
198 group.upper = upper;
199 }
200
201
202
203
204
205
206
207 public boolean isReinitVelocities() {
208 return group.reinitVelocities;
209 }
210
211 public void setReinitVelocities(boolean reinitVelocities) {
212 group.reinitVelocities = reinitVelocities;
213 }
214
215
216
217
218
219
220 public String getTemperString() {
221 return group.temperString;
222 }
223
224 public void setTemperString(String temperString) {
225 group.temperString = temperString;
226 }
227
228
229
230
231
232
233
234 public int getTemperBefore() {
235 return group.temperBefore;
236 }
237
238 public void setTemperBefore(int temperBefore) {
239 group.temperBefore = temperBefore;
240 }
241
242
243
244
245
246
247
248 public int getTemperAfter() {
249 return group.temperAfter;
250 }
251
252 public void setTemperAfter(int temperAfter) {
253 group.temperAfter = temperAfter;
254 }
255
256
257
258
259 private static class AnnealOptionGroup {
260
261
262
263
264 @Option(names = {"-W", "--windows"}, paramLabel = "10", defaultValue = "10",
265 description = "Number of annealing windows.")
266 private int windows = 10;
267
268
269
270
271 @Option(names = {"--tl", "--temperatureLow"}, paramLabel = "10.0", defaultValue = "10.0",
272 description = "Low temperature limit (Kelvin).")
273 private double low = 10.0;
274
275
276
277
278 @Option(names = {"--tu", "--temperatureUpper"}, paramLabel = "1000.0", defaultValue = "1000.0",
279 description = "High temperature limit (Kelvin).")
280 private double upper = 1000.0;
281
282
283
284
285
286
287 @Option(names = {"--rv", "--reinitVelocities"}, paramLabel = "false", defaultValue = "false",
288 description = "Re-initialize velocities before each round of annealing.")
289 private boolean reinitVelocities = false;
290
291
292
293
294 @Option(names = {"--tmS", "--temperingSchedule"}, paramLabel = "EXP", defaultValue = "EXP",
295 description = "Tempering schedule: choose between EXP (exponential) or LINEAR")
296 private String temperString = "EXP";
297
298
299
300
301
302 @Option(names = {"--tmB", "--temperingBefore"}, paramLabel = "0", defaultValue = "0",
303 description = "Number of (annealing, not MD/MC) steps to remain at the high temperature")
304 private int temperBefore = 0;
305
306
307
308
309
310 @Option(names = {"--tmA", "--temperingAfter"}, paramLabel = "0", defaultValue = "0",
311 description = "Number of (annealing, not MD/MC) steps to remain at the low temperature")
312 private int temperAfter = 0;
313 }
314 }