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.dynamics.MDEngine;
42 import ffx.algorithms.dynamics.MolecularDynamics;
43 import ffx.algorithms.thermodynamics.HistogramData;
44 import ffx.algorithms.thermodynamics.LambdaData;
45 import ffx.algorithms.thermodynamics.MonteCarloOST;
46 import ffx.algorithms.thermodynamics.OrthogonalSpaceTempering;
47 import ffx.algorithms.thermodynamics.OrthogonalSpaceTempering.OptimizationParameters;
48 import ffx.crystal.CrystalPotential;
49 import ffx.potential.MolecularAssembly;
50 import ffx.potential.bonded.LambdaInterface;
51 import ffx.potential.cli.WriteoutOptions;
52 import org.apache.commons.configuration2.CompositeConfiguration;
53 import org.apache.commons.configuration2.Configuration;
54 import picocli.CommandLine.ArgGroup;
55 import picocli.CommandLine.Option;
56
57 import javax.annotation.Nullable;
58 import java.io.File;
59 import java.util.logging.Logger;
60
61
62
63
64
65
66
67
68
69
70 public class OSTOptions {
71
72 private static final Logger logger = Logger.getLogger(OSTOptions.class.getName());
73
74
75
76
77 @ArgGroup(heading = "%n Orthogonal Space Tempering Options%n", validate = false)
78 private final OSTOptionGroup group = new OSTOptionGroup();
79
80
81
82
83 @ArgGroup(heading = "%n Monte Carlo Orthogonal Space Tempering Options%n", validate = false)
84 private final MCOSTOptionGroup mcGroup = new MCOSTOptionGroup();
85
86
87
88
89
90
91
92
93
94
95
96 public CrystalPotential applyAllOSTOptions(OrthogonalSpaceTempering orthogonalSpaceTempering,
97 MolecularAssembly firstAssembly, DynamicsOptions dynamicsOptions,
98 BarostatOptions barostatOptions) {
99 if (dynamicsOptions.getOptimize()) {
100 OptimizationParameters opt = orthogonalSpaceTempering.getOptimizationParameters();
101 opt.setOptimization(true, firstAssembly);
102 }
103 return barostatOptions.checkNPT(firstAssembly, orthogonalSpaceTempering);
104 }
105
106
107
108
109
110
111
112
113 public void beginMCOST(MonteCarloOST monteCarloOST, DynamicsOptions dynamicsOptions,
114 ThermodynamicsOptions thermodynamicsOptions) {
115 long nEquil = thermodynamicsOptions.getEquilSteps();
116
117 if (nEquil > 0) {
118 logger.info("\n Beginning MC-OST equilibration.");
119 monteCarloOST.setTotalSteps(nEquil);
120 if (mcGroup.twoStep) {
121 monteCarloOST.sampleTwoStep();
122 } else {
123 monteCarloOST.sampleOneStep();
124 }
125 monteCarloOST.setEquilibration(false);
126 logger.info("\n Finished MC-OST equilibration.");
127 }
128
129 logger.info("\n Beginning MC-OST sampling.");
130 monteCarloOST.setLambdaStdDev(mcGroup.mcLambdaStdDev);
131 monteCarloOST.setTotalSteps(dynamicsOptions.getSteps());
132
133 if (mcGroup.twoStep) {
134 monteCarloOST.sampleTwoStep();
135 } else {
136 monteCarloOST.sampleOneStep();
137 }
138 }
139
140
141
142
143
144
145
146
147
148
149 public MolecularDynamics assembleMolecularDynamics(MolecularAssembly[] molecularAssemblies,
150 CrystalPotential crystalPotential, DynamicsOptions dynamicsOptions,
151 AlgorithmListener algorithmListener) {
152
153 MolecularAssembly firstTop = molecularAssemblies[0];
154
155 dynamicsOptions.init();
156
157 MolecularDynamics molDyn = MolecularDynamics.dynamicsFactory(firstTop, crystalPotential,
158 algorithmListener, dynamicsOptions.thermostat, dynamicsOptions.integrator, MDEngine.FFX);
159 for (int i = 1; i < molecularAssemblies.length; i++) {
160 molDyn.addAssembly(molecularAssemblies[i]);
161 }
162 molDyn.setRestartFrequency(dynamicsOptions.getCheckpoint());
163
164 return molDyn;
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182 public OrthogonalSpaceTempering constructOST(CrystalPotential crystalPotential,
183 @Nullable File lambdaRestartFile,
184 File histogramRestartFile, MolecularAssembly firstAssembly,
185 @Nullable Configuration addedProperties,
186 DynamicsOptions dynamicsOptions, ThermodynamicsOptions thermodynamicsOptions,
187 LambdaParticleOptions lambdaParticleOptions,
188 @Nullable AlgorithmListener algorithmListener, boolean async) {
189
190 LambdaInterface lambdaInterface = (LambdaInterface) crystalPotential;
191 CompositeConfiguration compositeConfiguration = new CompositeConfiguration(firstAssembly.getProperties());
192 if (addedProperties != null) {
193 compositeConfiguration.addConfiguration(addedProperties);
194 }
195
196
197 HistogramData histogramData = HistogramData.readHistogram(histogramRestartFile);
198
199 int histogramIndex = 0;
200 if (histogramData.wasHistogramRead()) {
201 logger.info("\n Read histogram restart from: " + histogramRestartFile);
202 logger.info(histogramData.toString());
203 } else {
204
205 histogramData.applyProperties(compositeConfiguration);
206
207 histogramData.setIndependentWalkers(group.independentWalkers);
208 histogramData.setWriteIndependent(group.independentWalkers);
209 histogramData.setAsynchronous(async);
210 histogramData.setTemperingFactor(getTemperingParameter(histogramIndex));
211 if (thresholdsSet()) {
212 histogramData.setTemperingOffset(getTemperingThreshold(histogramIndex));
213 }
214 histogramData.setMetaDynamics(group.metaDynamics);
215 histogramData.setBiasMag(getBiasMag(histogramIndex));
216 histogramData.setCountInterval(group.countInterval);
217 logger.info("\n OST Histogram Settings");
218 logger.info(histogramData.toString());
219 }
220
221
222 if (lambdaRestartFile == null) {
223 String filename = histogramRestartFile.toString().replaceFirst("\\.his$", ".lam");
224 lambdaRestartFile = new File(filename);
225 }
226 LambdaData lambdaData = LambdaData.readLambdaData(lambdaRestartFile);
227
228 if (lambdaData.wasLambdaRead()) {
229 logger.info(" Read lambda restart from: " + lambdaRestartFile);
230 } else {
231 lambdaData.setHistogramIndex(histogramIndex);
232 if (thermodynamicsOptions.getResetNumSteps()) {
233 lambdaData.setStepsTaken(0);
234 }
235 }
236
237 OrthogonalSpaceTempering orthogonalSpaceTempering = new OrthogonalSpaceTempering(lambdaInterface,
238 crystalPotential, histogramData, lambdaData, compositeConfiguration,
239 dynamicsOptions, lambdaParticleOptions, algorithmListener);
240 orthogonalSpaceTempering.setHardWallConstraint(mcGroup.mcHardWall);
241
242
243 return orthogonalSpaceTempering;
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257
258 public void beginMDOST(OrthogonalSpaceTempering orthogonalSpaceTempering,
259 MolecularAssembly[] molecularAssemblies, CrystalPotential crystalPotential,
260 DynamicsOptions dynamicsOptions, WriteoutOptions writeoutOptions,
261 ThermodynamicsOptions thermodynamicsOptions, File dynFile,
262 AlgorithmListener algorithmListener) {
263
264 dynamicsOptions.init();
265
266 MolecularDynamics molDyn = assembleMolecularDynamics(molecularAssemblies, crystalPotential,
267 dynamicsOptions, algorithmListener);
268
269 boolean initVelocities = true;
270 long nSteps = dynamicsOptions.getSteps();
271
272 long nEquil = thermodynamicsOptions.getEquilSteps();
273 if (nEquil > 0) {
274 logger.info("\n Beginning equilibration");
275 orthogonalSpaceTempering.setPropagateLambda(false);
276 runDynamics(molDyn, nEquil, dynamicsOptions, writeoutOptions, true, dynFile);
277 logger.info(" Beginning OST sampling");
278 orthogonalSpaceTempering.setPropagateLambda(true);
279 } else {
280 logger.info(" Beginning OST sampling without equilibration");
281 if (!thermodynamicsOptions.getResetNumSteps()) {
282 long nEnergyCount = orthogonalSpaceTempering.getEnergyCount();
283 if (nEnergyCount > 0) {
284 nSteps -= nEnergyCount;
285 logger.info(String.format(" Lambda file: %12d steps picked up, now sampling %12d steps",
286 nEnergyCount, nSteps));
287 initVelocities = false;
288 }
289 }
290 }
291 if (nSteps > 0) {
292 runDynamics(molDyn, nSteps, dynamicsOptions, writeoutOptions, initVelocities, dynFile);
293 } else {
294 logger.info(" No steps remaining for this process!");
295 }
296 }
297
298
299
300
301
302
303 public boolean getIndependentWalkers() {
304 return group.independentWalkers;
305 }
306
307
308
309
310
311
312 public boolean isMonteCarlo() {
313 return mcGroup.monteCarlo;
314 }
315
316 public void setMonteCarlo(boolean monteCarlo) {
317 mcGroup.monteCarlo = monteCarlo;
318 }
319
320
321
322
323
324
325 public boolean isTwoStep() {
326 return mcGroup.twoStep;
327 }
328
329 public void setTwoStep(boolean twoStep) {
330 mcGroup.twoStep = twoStep;
331 }
332
333
334
335
336
337
338
339
340
341
342
343
344 public MonteCarloOST setupMCOST(OrthogonalSpaceTempering orthogonalSpaceTempering,
345 MolecularAssembly[] molecularAssemblies, DynamicsOptions dynamicsOptions,
346 ThermodynamicsOptions thermodynamicsOptions, boolean verbose,
347 File dynRestart, AlgorithmListener algorithmListener) {
348 dynamicsOptions.init();
349
350 MonteCarloOST monteCarloOST = new MonteCarloOST(orthogonalSpaceTempering.getPotentialEnergy(),
351 orthogonalSpaceTempering, molecularAssemblies[0], molecularAssemblies[0].getProperties(),
352 algorithmListener, dynamicsOptions, verbose, mcGroup.mcMDSteps, dynRestart);
353
354 MolecularDynamics md = monteCarloOST.getMD();
355 for (int i = 1; i < molecularAssemblies.length; i++) {
356 md.addAssembly(molecularAssemblies[i]);
357 }
358
359 long nEquil = thermodynamicsOptions.getEquilSteps();
360 if (nEquil > 0) {
361 monteCarloOST.setEquilibration(true);
362 }
363 return monteCarloOST;
364 }
365
366 private boolean thresholdsSet() {
367 return group.temperingThreshold.length != 1 || group.temperingThreshold[0] >= 0;
368 }
369
370
371
372
373
374
375
376 private double getBiasMag(int i) {
377 return group.biasMag.length > 1 ? group.biasMag[i] : group.biasMag[0];
378 }
379
380 private void runDynamics(MolecularDynamics molecularDynamics, long numSteps,
381 DynamicsOptions dynamicsOptions, WriteoutOptions writeoutOptions, boolean initVelocities,
382 File dyn) {
383 molecularDynamics.dynamic(numSteps, dynamicsOptions.getDt(), dynamicsOptions.getReport(),
384 dynamicsOptions.getWrite(), dynamicsOptions.getTemperature(), initVelocities,
385 writeoutOptions.getFileType(), dynamicsOptions.getCheckpoint(), dyn);
386 }
387
388
389
390
391
392
393
394 private double getTemperingThreshold(int i) {
395 return group.temperingThreshold.length > 1 ? group.temperingThreshold[i]
396 : group.temperingThreshold[0];
397 }
398
399
400
401
402
403
404
405 private double getTemperingParameter(int i) {
406 return group.temperingRate.length > 1 ? group.temperingRate[i] : group.temperingRate[0];
407 }
408
409
410
411
412
413
414 public int getCountInterval() {
415 return group.countInterval;
416 }
417
418 public void setCountInterval(int countInterval) {
419 group.countInterval = countInterval;
420 }
421
422
423
424
425
426
427 public double[] getBiasMag() {
428 return group.biasMag;
429 }
430
431 public void setBiasMag(double[] biasMag) {
432 group.biasMag = biasMag;
433 }
434
435
436
437
438
439
440 public boolean isIndependentWalkers() {
441 return group.independentWalkers;
442 }
443
444 public void setIndependentWalkers(boolean independentWalkers) {
445 group.independentWalkers = independentWalkers;
446 }
447
448
449
450
451
452
453 public boolean isMetaDynamics() {
454 return group.metaDynamics;
455 }
456
457 public void setMetaDynamics(boolean metaDynamics) {
458 group.metaDynamics = metaDynamics;
459 }
460
461
462
463
464
465
466 public double[] getTemperingRate() {
467 return group.temperingRate;
468 }
469
470 public void setTemperingRate(double[] temperingRate) {
471 group.temperingRate = temperingRate;
472 }
473
474
475
476
477
478
479 public double[] getTemperingThreshold() {
480 return group.temperingThreshold;
481 }
482
483 public void setTemperingThreshold(double[] temperingThreshold) {
484 group.temperingThreshold = temperingThreshold;
485 }
486
487
488
489
490
491
492
493 public boolean isMcHardWall() {
494 return mcGroup.mcHardWall;
495 }
496
497 public void setMcHardWall(boolean mcHardWall) {
498 mcGroup.mcHardWall = mcHardWall;
499 }
500
501
502
503
504
505
506 public int getMcMDSteps() {
507 return mcGroup.mcMDSteps;
508 }
509
510 public void setMcMDSteps(int mcMDSteps) {
511 mcGroup.mcMDSteps = mcMDSteps;
512 }
513
514
515
516
517
518
519 public double getMcLambdaStdDev() {
520 return mcGroup.mcLambdaStdDev;
521 }
522
523 public void setMcLambdaStdDev(double mcLambdaStdDev) {
524 mcGroup.mcLambdaStdDev = mcLambdaStdDev;
525 }
526
527
528
529
530
531
532 public double getLambdaWriteOut() {
533 return group.lambdaWriteOut;
534 }
535
536 public void setLambdaWriteOut(double lambdaWriteOut) {
537 group.lambdaWriteOut = lambdaWriteOut;
538 }
539
540
541
542
543 private static class OSTOptionGroup {
544
545
546
547
548 @Option(names = {"-C", "--count"}, paramLabel = "10", defaultValue = "10",
549 description = "Time steps between MD Orthogonal Space counts.")
550 private int countInterval = 10;
551
552
553
554
555 @Option(names = {"--bM", "--biasMag"}, paramLabel = "0.05", defaultValue = "0.05", split = ",",
556 description = "Orthogonal Space Gaussian bias magnitude (kcal/mol); RepEx OST uses a comma-separated list.")
557 private double[] biasMag = {0.05};
558
559
560
561
562 @Option(names = {"--iW", "--independentWalkers"}, defaultValue = "false",
563 description = "Enforces that each walker maintains their own histogram.")
564 private boolean independentWalkers = false;
565
566
567
568
569 @Option(names = {"--meta", "--metaDynamics"}, defaultValue = "false",
570 description = "Use a 1D metadynamics style bias.")
571 private boolean metaDynamics = false;
572
573
574
575
576 @Option(names = {"--tp", "--temperingRate"}, paramLabel = "4.0", defaultValue = "4.0", split = ",",
577 description = "Tempering rate parameter in multiples of kBT; RepEx OST uses a comma-separated list.")
578 private double[] temperingRate = {4.0};
579
580
581
582
583 @Option(names = {"--tth", "--temperingThreshold"}, paramLabel = "20*bias", defaultValue = "-1", split = ",",
584 description = "Tempering threshold in kcal/mol; RepEx OST uses a comma-separated list.")
585 private double[] temperingThreshold = {-1.0};
586
587
588
589
590
591 @Option(names = {"--lw", "--lambdaWriteOut"}, paramLabel = "0.0", defaultValue = "0.0",
592 description = "Only write out snapshots if lambda is greater than the value specified.")
593 private double lambdaWriteOut = 0.0;
594 }
595
596
597
598
599 private static class MCOSTOptionGroup {
600
601
602
603
604 @Option(names = {"--mc", "--monteCarlo"}, defaultValue = "false",
605 description = "Specify use of Monte Carlo OST")
606 private boolean monteCarlo = false;
607
608
609
610
611
612 @Option(names = {"--mcHW", "--mcHardWall"}, defaultValue = "false",
613 description = "Monte Carlo OST hard wall constraint.")
614 private boolean mcHardWall = false;
615
616
617
618
619 @Option(names = {"--mcMD", "--mcMDSteps"}, paramLabel = "100", defaultValue = "100",
620 description = "Number of dynamics steps to take for each MD trajectory for Monte Carlo OST")
621 private int mcMDSteps = 100;
622
623
624
625
626 @Option(names = {"--mcL", "--mcLambdaStdDev"}, paramLabel = "0.01", defaultValue = "0.01",
627 description = "Standard deviation for lambda move.")
628 private double mcLambdaStdDev = 0.01;
629
630
631
632
633 @Option(names = {"--ts", "--twoStep"}, defaultValue = "false",
634 description = "MC Orthogonal Space sampling using separate lambda and MD moves.")
635 private boolean twoStep = false;
636 }
637
638 }