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 ffx.algorithms.AlgorithmListener;
41 import ffx.algorithms.cli.DynamicsOptions;
42 import ffx.algorithms.dynamics.MDVerbosity;
43 import ffx.algorithms.dynamics.MDWriteAction;
44 import ffx.algorithms.dynamics.MolecularDynamics;
45 import ffx.algorithms.dynamics.MolecularDynamicsOpenMM;
46 import ffx.numerics.Potential;
47 import ffx.potential.MolecularAssembly;
48 import ffx.utilities.Constants;
49
50 import javax.annotation.Nullable;
51 import java.io.File;
52 import java.util.EnumSet;
53 import java.util.logging.Level;
54 import java.util.logging.Logger;
55
56 import static java.lang.Math.abs;
57 import static java.lang.Math.min;
58 import static java.lang.String.format;
59
60
61
62
63
64
65 public class MDMove implements MCMove {
66
67 private static final Logger logger = Logger.getLogger(MDMove.class.getName());
68
69
70
71
72 private final MolecularDynamics molecularDynamics;
73
74
75
76 private final long mdSteps;
77
78
79
80 private final double timeStep;
81
82
83
84 private final double printInterval;
85
86
87
88 private final double temperature;
89
90
91
92 private final double saveInterval;
93
94
95
96 private final Potential potential;
97
98
99
100 private int mdMoveCounter = 0;
101
102
103
104 private double energyChange;
105
106
107
108 private double energyDriftAbs;
109
110
111
112 private double energyDriftNet;
113
114
115
116 private double initialKinetic;
117
118
119
120 private double initialPotential;
121
122
123
124 private double initialTotal;
125
126 private File dynRestartFile;
127
128
129
130
131
132
133
134
135
136
137
138 public MDMove(MolecularAssembly assembly, Potential potentialEnergy, AlgorithmListener listener,
139 DynamicsOptions dynamics, long stepsPerCycle, @Nullable File dynRestartFile) {
140 this.potential = potentialEnergy;
141 molecularDynamics = MolecularDynamics.dynamicsFactory(assembly, potentialEnergy, listener,
142 dynamics.thermostat, dynamics.integrator);
143 molecularDynamics.setAutomaticWriteouts(false);
144
145 timeStep = dynamics.getDt();
146 double dtPs = timeStep * Constants.FSEC_TO_PSEC;
147 mdSteps = stepsPerCycle;
148
149 molecularDynamics.setVerbosityLevel(MDVerbosity.QUIET);
150 molecularDynamics.setObtainVelAcc(false);
151 molecularDynamics.setRestartFrequency(dynamics.getCheckpoint());
152 this.saveInterval = dynamics.getSnapshotInterval();
153
154 double requestedPrint = dynamics.getReport();
155 double maxPrintInterval = dtPs * mdSteps;
156
157 printInterval = min(requestedPrint, maxPrintInterval);
158 this.temperature = dynamics.getTemperature();
159
160 this.dynRestartFile = dynRestartFile;
161
162 if (this.dynRestartFile != null && this.dynRestartFile.exists()) {
163 molecularDynamics.setVerbosityLevel(MDVerbosity.SILENT);
164 molecularDynamics.dynamic(1, timeStep, printInterval, saveInterval, temperature, false, dynRestartFile);
165 collectEnergies();
166 revertMove();
167 molecularDynamics.setVerbosityLevel(MDVerbosity.QUIET);
168 }
169 }
170
171
172
173
174
175
176 public double getEnergyChange() {
177 return energyChange;
178 }
179
180 public double getInitialKinetic() {
181 return initialKinetic;
182 }
183
184 public double getInitialPotential() {
185 return initialPotential;
186 }
187
188 public double getInitialTotal() {
189 return initialTotal;
190 }
191
192
193
194
195
196
197 public double getKineticEnergy() {
198 return molecularDynamics.getKineticEnergy();
199 }
200
201 public MolecularDynamics getMD() {
202 return molecularDynamics;
203 }
204
205
206
207
208
209
210 public double getPotentialEnergy() {
211 return molecularDynamics.getPotentialEnergy();
212 }
213
214
215
216
217 @Override
218 public void move() {
219 move(MDVerbosity.QUIET);
220 }
221
222
223
224
225
226
227 public void move(MDVerbosity verbosityLevel) {
228 MDVerbosity origLevel = molecularDynamics.getVerbosityLevel();
229 molecularDynamics.setVerbosityLevel(verbosityLevel);
230 if (mdMoveCounter == 0 && dynRestartFile != null && dynRestartFile.exists()) {
231 molecularDynamics.dynamic(mdSteps, timeStep, printInterval, saveInterval, temperature, false, dynRestartFile);
232 } else {
233 molecularDynamics.dynamic(mdSteps, timeStep, printInterval, saveInterval, temperature, true, null);
234 }
235 mdMoveCounter++;
236 collectEnergies();
237 energyChange = molecularDynamics.getTotalEnergy() - initialTotal;
238
239 if (molecularDynamics instanceof MolecularDynamicsOpenMM && logger.isLoggable(Level.FINE)) {
240 energyDriftNet += energyChange;
241 energyDriftAbs += abs(energyChange);
242 double energyDriftAverageNet = energyDriftNet / mdMoveCounter;
243 double energyDriftAverageAbs = energyDriftAbs / mdMoveCounter;
244 logger.fine(format(" Mean signed/unsigned energy drift: %8.4f/%8.4f",
245 energyDriftAverageNet, energyDriftAverageAbs));
246
247 double dt = molecularDynamics.getTimeStep();
248 int intervalSteps = molecularDynamics.getIntervalSteps();
249 int nAtoms = potential.getNumberOfVariables() / 3;
250
251
252 double normalizedEnergyDriftNet = (energyDriftAverageNet / (dt * intervalSteps * nAtoms)) * 1000;
253 double normalizedEnergyDriftAbs = (energyDriftAverageAbs / (dt * intervalSteps * nAtoms)) * 1000;
254 logger.fine(format(" Mean singed/unsigned energy drift per psec per atom: %8.4f/%8.4f\n",
255 normalizedEnergyDriftNet, normalizedEnergyDriftAbs));
256 }
257 molecularDynamics.setVerbosityLevel(origLevel);
258 }
259
260
261
262
263 @Override
264 public void revertMove() {
265 try {
266 molecularDynamics.revertState();
267 } catch (Exception ex) {
268 logger.severe(" The MD state could not be reverted.");
269 }
270 }
271
272 public void setMDIntervalSteps(int intervalSteps) {
273 molecularDynamics.setIntervalSteps(intervalSteps);
274 }
275
276
277
278
279
280
281
282
283
284 public EnumSet<MDWriteAction> writeFilesForStep(long mdStep, boolean trySnapshot, boolean tryRestart) {
285 return molecularDynamics.writeFilesForStep(mdStep, trySnapshot, tryRestart);
286 }
287
288 private void collectEnergies() {
289 initialTotal = molecularDynamics.getInitialTotalEnergy();
290 initialKinetic = molecularDynamics.getInitialKineticEnergy();
291 initialPotential = molecularDynamics.getInitialPotentialEnergy();
292
293 assert abs(initialTotal) < 1.0E-3
294 || abs((initialKinetic + initialPotential - initialTotal) / initialTotal) < 1.0E-7;
295 }
296 }