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 static java.lang.String.format;
41
42 import ffx.algorithms.AlgorithmListener;
43 import ffx.algorithms.dynamics.MolecularDynamics;
44 import ffx.crystal.CrystalPotential;
45 import ffx.potential.MolecularAssembly;
46 import ffx.potential.cli.WriteoutOptions;
47
48 import java.io.File;
49 import java.util.Arrays;
50 import java.util.Collections;
51 import java.util.Set;
52 import java.util.TreeSet;
53 import java.util.logging.Logger;
54
55 import picocli.CommandLine.ArgGroup;
56 import picocli.CommandLine.Option;
57
58
59
60
61
62
63
64
65 public class ThermodynamicsOptions {
66
67 private static final Logger logger = Logger.getLogger(ThermodynamicsOptions.class.getName());
68
69
70
71
72 @ArgGroup(heading = "%n Thermodynamics Options%n", validate = false)
73 private final ThermodynamicsOptionGroup group = new ThermodynamicsOptionGroup();
74
75
76
77
78
79
80 public ThermodynamicsAlgorithm getAlgorithm() {
81 return ThermodynamicsAlgorithm.parse(group.thermoAlgoString);
82 }
83
84
85
86
87
88
89 public long getEquilSteps() {
90 return group.equilibrationSteps;
91 }
92
93
94
95
96
97
98 public boolean getResetNumSteps() {
99 return group.resetNumSteps;
100 }
101
102
103
104
105
106
107
108
109
110
111
112
113 public MolecularDynamics runFixedAlchemy(MolecularAssembly[] molecularAssemblies,
114 CrystalPotential crystalPotential, DynamicsOptions dynamicsOptions,
115 WriteoutOptions writeoutOptions, File dyn, AlgorithmListener algorithmListener) {
116 dynamicsOptions.init();
117
118 MolecularDynamics molDyn = dynamicsOptions.getDynamics(writeoutOptions, crystalPotential,
119 molecularAssemblies[0], algorithmListener);
120 for (int i = 1; i < molecularAssemblies.length; i++) {
121 molDyn.addAssembly(molecularAssemblies[i]);
122 }
123
124 boolean initVelocities = true;
125 long nSteps = dynamicsOptions.getSteps();
126 molDyn.setRestartFrequency(dynamicsOptions.getCheckpoint());
127
128 if (group.equilibrationSteps > 0) {
129 logger.info("\n Beginning Equilibration");
130 runDynamics(molDyn, group.equilibrationSteps, dynamicsOptions, writeoutOptions, true, dyn);
131 logger.info(" Beginning Fixed-Lambda Alchemical Sampling");
132 initVelocities = false;
133 } else {
134 logger.info("\n Beginning Fixed-Lambda Alchemical Sampling Without Equilibration");
135 if (!group.resetNumSteps) {
136
137 initVelocities = true;
138 }
139 }
140
141 if (nSteps > 0) {
142 runDynamics(molDyn, nSteps, dynamicsOptions, writeoutOptions, initVelocities, dyn);
143 } else {
144 logger.info(" No steps remaining for this process!");
145 }
146 return molDyn;
147 }
148
149
150
151
152
153
154 public long getEquilibrationSteps() {
155 return group.equilibrationSteps;
156 }
157
158 private void runDynamics(MolecularDynamics molecularDynamics, long nSteps,
159 DynamicsOptions dynamicsOptions, WriteoutOptions writeoutOptions, boolean initVelocities,
160 File dyn) {
161 molecularDynamics.dynamic(nSteps, dynamicsOptions.getDt(), dynamicsOptions.getReport(),
162 dynamicsOptions.getWrite(), dynamicsOptions.getTemperature(), initVelocities,
163 writeoutOptions.getFileType(), dynamicsOptions.getCheckpoint(), dyn);
164 }
165
166 public void setEquilibrationSteps(long equilibrationSteps) {
167 group.equilibrationSteps = equilibrationSteps;
168 }
169
170
171
172
173
174
175 public boolean isResetNumSteps() {
176 return group.resetNumSteps;
177 }
178
179 public void setResetNumSteps(boolean resetNumSteps) {
180 group.resetNumSteps = resetNumSteps;
181 }
182
183
184
185
186
187
188 public String getThermoAlgoString() {
189 return group.thermoAlgoString;
190 }
191
192 public void setThermoAlgoString(String thermoAlgoString) {
193 group.thermoAlgoString = thermoAlgoString;
194 }
195
196
197
198
199 private static class ThermodynamicsOptionGroup {
200
201
202
203
204
205 @Option(names = {"-Q", "--equilibrate"}, paramLabel = "1000", defaultValue = "1000",
206 description = "Number of equilibration steps before evaluation of thermodynamics.")
207 private long equilibrationSteps = 1000;
208
209
210
211
212
213 @Option(names = {"--rn", "--resetNumSteps"}, defaultValue = "false",
214 description = "Ignore prior steps logged in .lam or similar files")
215 private boolean resetNumSteps = false;
216
217
218
219
220
221 @Option(names = {"--tA", "--thermodynamicsAlgorithm"}, paramLabel = "OST", defaultValue = "OST",
222 description = "Choice of thermodynamics algorithm. The default is OST, while FIXED runs MD at a fixed lambda value (e.g. BAR)")
223 private String thermoAlgoString = "OST";
224 }
225
226
227
228
229
230
231 public enum ThermodynamicsAlgorithm {
232
233
234 OST("OST", "MC-OST", "MD-OST", "DEFAULT"), FIXED("BAR", "MBAR", "FEP", "WINDOWED");
235
236 private final Set<String> aliases;
237
238 ThermodynamicsAlgorithm(String... aliases) {
239
240 Set<String> names = new TreeSet<>(Arrays.asList(aliases));
241 names.add(this.name());
242 this.aliases = Collections.unmodifiableSet(names);
243 }
244
245
246
247
248
249
250
251
252
253 public static ThermodynamicsAlgorithm parse(String name) throws IllegalArgumentException {
254 String ucName = name.toUpperCase();
255 for (ThermodynamicsAlgorithm thermodynamicsAlgorithm : values()) {
256 if (thermodynamicsAlgorithm.aliases.contains(ucName)) {
257 return thermodynamicsAlgorithm;
258 }
259 }
260 throw new IllegalArgumentException(
261 format(" Could not parse %s as a ThermodynamicsAlgorithm", name));
262 }
263 }
264 }