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.dynamics.integrators;
39
40 import static ffx.utilities.Constants.KCAL_TO_GRAM_ANG2_PER_PS2;
41 import static ffx.utilities.Constants.kB;
42 import static java.lang.System.arraycopy;
43 import static java.util.Arrays.copyOf;
44 import static org.apache.commons.math3.util.FastMath.exp;
45 import static org.apache.commons.math3.util.FastMath.sqrt;
46
47 import ffx.numerics.Constraint;
48 import ffx.potential.SystemState;
49 import ffx.numerics.Potential;
50 import ffx.potential.constraint.ShakeChargeConstraint;
51
52 import java.util.Random;
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public class Stochastic extends Integrator {
67
68
69
70
71 private final double friction;
72
73
74
75 private final Random random;
76
77
78
79 private final double[] vFriction;
80
81
82
83 private final double[] vRandom;
84
85
86
87 private double inverseFriction;
88
89
90
91 private double fdt;
92
93
94
95 private double efdt;
96
97
98
99 private double temperature;
100 private double[] xPrior;
101 private final int nVariables;
102 private double[] africArray;
103
104
105
106
107
108
109
110 public Stochastic(double friction, SystemState state) {
111 super(state);
112 this.friction = friction;
113 if (friction >= 0) {
114 inverseFriction = 1.0 / friction;
115 } else {
116 inverseFriction = Double.POSITIVE_INFINITY;
117 }
118 nVariables = state.getNumberOfVariables();
119 vFriction = new double[nVariables];
120 vRandom = new double[nVariables];
121 fdt = friction * dt;
122 efdt = exp(-fdt);
123 temperature = 298.15;
124 random = new Random();
125 }
126
127
128
129
130
131
132
133 @Override
134 public void postForce(double[] gradient) {
135 copyAccelerationToPrevious();
136 double[] a = state.a();
137 double[] v = state.v();
138 double[] mass = state.getMass();
139 for (int i = 0; i < state.getNumberOfVariables(); i++) {
140 double m = mass[i];
141 if (m > 0.0) {
142 a[i] = -KCAL_TO_GRAM_ANG2_PER_PS2 * gradient[i] / m;
143 v[i] += (0.5 * a[i] * vFriction[i] + vRandom[i]);
144 }
145 }
146 }
147
148
149
150
151
152
153
154 @Override
155 public void preForce(Potential potential) throws RuntimeException {
156 double[] mass = state.getMass();
157 double[] x = state.x();
158 double[] v = state.v();
159 double[] a = state.a();
160 if (useConstraints) {
161 if (xPrior == null) {
162 xPrior = copyOf(x, nVariables);
163 } else {
164 arraycopy(x, 0, xPrior, 0, nVariables);
165 }
166 if(africArray == null){
167 africArray = new double[nVariables];
168 }
169 }
170 for (int i = 0; i < state.getNumberOfVariables(); i++) {
171 double m = mass[i];
172 double afric;
173 double pfric;
174 double prand;
175 if (fdt <= 0.0) {
176
177 pfric = 1.0;
178 vFriction[i] = dt;
179 afric = 0.5 * dt * dt;
180 prand = 0.0;
181 vRandom[i] = 0.0;
182 } else {
183 double pterm;
184 double vterm;
185 double rho;
186 if (fdt >= 0.05) {
187
188 pfric = efdt;
189 vFriction[i] = (1.0 - efdt) * inverseFriction;
190 afric = (dt - vFriction[i]) * inverseFriction;
191 pterm = 2.0 * fdt - 3.0 + (4.0 - efdt) * efdt;
192 vterm = 1.0 - efdt * efdt;
193 rho = (1.0 - efdt) * (1.0 - efdt) / sqrt(pterm * vterm);
194 } else {
195
196 double fdt2 = fdt * fdt;
197 double fdt3 = fdt * fdt2;
198 double fdt4 = fdt * fdt3;
199 double fdt5 = fdt * fdt4;
200 double fdt6 = fdt * fdt5;
201 double fdt7 = fdt * fdt6;
202 double fdt8 = fdt * fdt7;
203 double fdt9 = fdt * fdt8;
204 afric =
205 (fdt2 / 2.0 - fdt3 / 6.0 + fdt4 / 24.0 - fdt5 / 120.0 + fdt6 / 720.0 - fdt7 / 5040.0
206 + fdt8 / 40320.0 - fdt9 / 362880.0) / (friction * friction);
207 vFriction[i] = dt - friction * afric;
208 pfric = 1.0 - friction * vFriction[i];
209 pterm =
210 2.0 * fdt3 / 3.0 - fdt4 / 2.0 + 7.0 * fdt5 / 30.0 - fdt6 / 12.0 + 31.0 * fdt7 / 1260.0
211 - fdt8 / 160.0 + 127.0 * fdt9 / 90720.0;
212 vterm = 2.0 * fdt - 2.0 * fdt2 + 4.0 * fdt3 / 3.0 - 2.0 * fdt4 / 3.0 + 4.0 * fdt5 / 15.0
213 - 4.0 * fdt6 / 45.0 + 8.0 * fdt7 / 315.0 - 2.0 * fdt8 / 315.0 + 4.0 * fdt9 / 2835.0;
214 rho = sqrt(3.0) * (0.5 - fdt / 16.0 - 17.0 * fdt2 / 1280.0 + 17.0 * fdt3 / 6144.0
215 + 40967.0 * fdt4 / 34406400.0 - 57203.0 * fdt5 / 275251200.0
216 - 1429487.0 * fdt6 / 13212057600.0 + 1877509.0 * fdt7 / 105696460800.0);
217 }
218
219 double ktm = kB * temperature / m;
220 double psig = sqrt(ktm * pterm) / friction;
221 double vsig = sqrt(ktm * vterm);
222 double rhoc = sqrt(1.0 - rho * rho);
223 double pnorm = random.nextGaussian();
224 double vnorm = random.nextGaussian();
225 prand = psig * pnorm;
226 vRandom[i] = vsig * (rho * pnorm + rhoc * vnorm);
227 }
228
229
230
231 x[i] += (v[i] * vFriction[i] + a[i] * afric + prand);
232 v[i] = v[i] * pfric + 0.5 * a[i] * vFriction[i];
233
234 if(useConstraints){
235 africArray[i] = afric;
236 }
237 }
238 if (useConstraints) {
239 for(Constraint c : constraints){
240 if(c instanceof ShakeChargeConstraint){
241 ((ShakeChargeConstraint) c).applyChargeConstraintToStep(x, africArray, mass, dt);
242 double velScale = 1.0 / dt;
243 for (int i = 0; i < nVariables; i++) {
244 v[i] = velScale * (x[i] - xPrior[i]);
245 }
246 } else {
247 c.applyConstraintToStep(xPrior, x, mass, constraintTolerance);
248 }
249 }
250 }
251 }
252
253
254
255
256
257
258 public void setRandomSeed(long seed) {
259 random.setSeed(seed);
260 }
261
262
263
264
265
266
267 public void setTemperature(double temperature) {
268 this.temperature = temperature;
269 }
270
271
272
273
274
275
276 @Override
277 public void setTimeStep(double dt) {
278 this.dt = dt;
279 fdt = friction * dt;
280 efdt = exp(-fdt);
281 if (friction >= 0) {
282 inverseFriction = 1.0 / friction;
283 } else {
284 inverseFriction = Double.POSITIVE_INFINITY;
285 }
286 }
287
288
289
290
291 @Override
292 public String toString() {
293 return "Stochastic";
294 }
295 }