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.optimize;
39
40 import ffx.algorithms.AlgorithmListener;
41 import ffx.numerics.Potential;
42 import ffx.numerics.optimization.LineSearch;
43 import ffx.potential.ForceFieldEnergy;
44 import ffx.potential.MolecularAssembly;
45 import ffx.potential.bonded.Atom;
46 import ffx.potential.openmm.OpenMMContext;
47 import ffx.potential.openmm.OpenMMEnergy;
48 import ffx.potential.openmm.OpenMMState;
49
50 import java.util.logging.Logger;
51
52 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_State_DataType.OpenMM_State_Energy;
53 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_State_DataType.OpenMM_State_Forces;
54 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_State_DataType.OpenMM_State_Positions;
55 import static java.lang.Double.isInfinite;
56 import static java.lang.Double.isNaN;
57 import static java.lang.String.format;
58 import static org.apache.commons.math3.util.FastMath.sqrt;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 public class MinimizeOpenMM extends Minimize {
76
77 private static final Logger logger = Logger.getLogger(MinimizeOpenMM.class.getName());
78
79
80
81
82
83
84 public MinimizeOpenMM(MolecularAssembly molecularAssembly) {
85 super(molecularAssembly, molecularAssembly.getPotentialEnergy(), null);
86 }
87
88
89
90
91
92
93
94 public MinimizeOpenMM(MolecularAssembly molecularAssembly, OpenMMEnergy openMMEnergy) {
95 super(molecularAssembly, openMMEnergy, null);
96 }
97
98
99
100
101
102
103
104
105 public MinimizeOpenMM(MolecularAssembly molecularAssembly, OpenMMEnergy openMMEnergy, AlgorithmListener algorithmListener) {
106 super(molecularAssembly, openMMEnergy, algorithmListener);
107 }
108
109
110
111
112
113
114
115
116
117
118 @Override
119 public Potential minimize(int m, double eps, int maxIterations) {
120 return minimize(eps, maxIterations);
121 }
122
123
124
125
126
127
128
129
130 @Override
131 public Potential minimize(double eps, int maxIterations) {
132
133 ForceFieldEnergy forceFieldEnergy = molecularAssembly.getPotentialEnergy();
134
135 if (forceFieldEnergy instanceof OpenMMEnergy openMMEnergy) {
136 time = -System.nanoTime();
137
138
139 Atom[] atoms = molecularAssembly.getAtomArray();
140 openMMEnergy.updateParameters(atoms);
141
142
143 openMMEnergy.setActiveAtoms();
144
145
146 openMMEnergy.getCoordinates(x);
147
148
149 double e = openMMEnergy.energy(x);
150 logger.info(format("\n Initial energy: %12.6f (kcal/mol)", e));
151
152
153 OpenMMContext openMMContext = openMMEnergy.getContext();
154 openMMContext.optimize(eps, maxIterations);
155
156
157 int mask = OpenMM_State_Energy | OpenMM_State_Positions | OpenMM_State_Forces;
158 OpenMMState openMMState = openMMContext.getOpenMMState(mask);
159 energy = openMMState.potentialEnergy;
160 openMMState.getPositions(x);
161 openMMState.getGradient(grad);
162 openMMState.destroy();
163
164
165 int index = 0;
166 double grad2 = 0;
167 for (Atom atom : atoms) {
168 if (atom.isActive()) {
169 double fx = grad[index++];
170 double fy = grad[index++];
171 double fz = grad[index++];
172 grad2 += fx * fx + fy * fy + fz * fz;
173 }
174 }
175 rmsGradient = sqrt(grad2 / n);
176
177 double[] ffxGrad = new double[n];
178 openMMEnergy.getCoordinates(x);
179 double ffxEnergy = openMMEnergy.energyAndGradientFFX(x, ffxGrad);
180 double grmsFFX = 0.0;
181 for (int i = 0; i < n; i++) {
182 double gi = ffxGrad[i];
183 if (isNaN(gi) || isInfinite(gi)) {
184 String message = format(" The gradient of variable %d is %8.3f.", i, gi);
185 logger.warning(message);
186 }
187 grmsFFX += gi * gi;
188 }
189 grmsFFX = sqrt(grmsFFX / n);
190
191 time += System.nanoTime();
192 logger.info(format(" Final energy for OpenMM %12.6f vs. FFX %12.6f in %8.3f (sec).", energy, ffxEnergy, time * 1.0e-9));
193 logger.info(format(" Convergence criteria for OpenMM %12.6f vs. FFX %12.6f (kcal/mol/A).", rmsGradient, grmsFFX));
194 }
195
196 if (algorithmListener != null) {
197 algorithmListener.algorithmUpdate(molecularAssembly);
198 }
199
200 return forceFieldEnergy;
201 }
202
203
204
205
206
207
208 @Override
209 public boolean optimizationUpdate(int iteration, int nBFGS, int functionEvaluations,
210 double rmsGradient, double rmsCoordinateChange, double energy, double energyChange,
211 double angle, LineSearch.LineSearchResult lineSearchResult) {
212 logger.warning(" MinimizeOpenMM does not support updates at each optimization step.");
213 return false;
214 }
215 }