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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 package ffx.potential.constraint;
73
74 import ffx.numerics.Constraint;
75 import ffx.potential.bonded.Angle;
76 import ffx.potential.bonded.Atom;
77 import ffx.potential.bonded.Bond;
78
79 import java.util.logging.Logger;
80
81 import static ffx.numerics.math.DoubleMath.dot;
82 import static ffx.numerics.math.DoubleMath.normalize;
83 import static ffx.numerics.math.DoubleMath.sub;
84 import static java.lang.System.arraycopy;
85 import static org.apache.commons.math3.util.FastMath.abs;
86 import static org.apache.commons.math3.util.FastMath.cos;
87 import static org.apache.commons.math3.util.FastMath.sqrt;
88 import static org.apache.commons.math3.util.FastMath.toRadians;
89
90
91
92
93
94
95
96
97
98
99
100 public class SettleConstraint implements Constraint {
101
102 private static final Logger logger = Logger.getLogger(SettleConstraint.class.getName());
103
104 private final int index0;
105 private final int index1;
106 private final int index2;
107
108 private final double distance1;
109
110 private final double distance2;
111
112
113
114
115
116
117
118 private SettleConstraint(Angle a012) {
119 Atom center = a012.getCentralAtom();
120 index0 = center.getXyzIndex() - 1;
121
122 Bond b01 = a012.getBond(0);
123 Bond b02 = a012.getBond(1);
124
125 assert b01.bondType.distance == b02.bondType.distance;
126
127 distance1 = b01.bondType.distance;
128
129 Atom a1 = b01.get1_2(center);
130 Atom a2 = b02.get1_2(center);
131 index1 = a1.getXyzIndex() - 1;
132 index2 = a2.getXyzIndex() - 1;
133
134 double angVal = a012.angleType.angle[a012.nh];
135 distance2 = lawOfCosines(distance1, distance1, angVal);
136 }
137
138
139
140
141
142
143
144
145 public static SettleConstraint settleFactory(Angle a012) {
146 SettleConstraint newC = new SettleConstraint(a012);
147 a012.setConstraint(newC);
148 return newC;
149 }
150
151
152
153
154
155
156
157
158
159
160 static double lawOfCosines(double distAB, double distBC, double angABC) {
161 double val = distAB * distAB;
162 val += distBC * distBC;
163 val -= (2.0 * distAB * distBC * cos(toRadians(angABC)));
164 val = sqrt(val);
165 return val;
166 }
167
168 @Override
169 public void applyConstraintToStep(
170 final double[] xPrior, double[] xNew, final double[] masses, double tol) {
171
172
173
174
175 int xi0 = 3 * index0;
176 int xi1 = 3 * index1;
177 int xi2 = 3 * index2;
178
179
180 double[] apos0 = new double[3];
181 double[] apos1 = new double[3];
182 double[] apos2 = new double[3];
183
184
185 double[] xp0 = new double[3];
186 double[] xp1 = new double[3];
187 double[] xp2 = new double[3];
188
189 for (int i = 0; i < 3; i++) {
190 apos0[i] = xPrior[xi0 + i];
191 xp0[i] = xNew[xi0 + i] - apos0[i];
192 apos1[i] = xPrior[xi1 + i];
193 xp1[i] = xNew[xi1 + i] - apos1[i];
194 apos2[i] = xPrior[xi2 + i];
195 xp2[i] = xNew[xi2 + i] - apos2[i];
196 }
197
198 double m0 = masses[xi0];
199 double m1 = masses[xi1];
200 double m2 = masses[xi2];
201
202
203
204 double xb0 = apos1[0] - apos0[0];
205 double yb0 = apos1[1] - apos0[1];
206 double zb0 = apos1[2] - apos0[2];
207 double xc0 = apos2[0] - apos0[0];
208 double yc0 = apos2[1] - apos0[1];
209 double zc0 = apos2[2] - apos0[2];
210
211 double invTotalMass = 1.0 / (m0 + m1 + m2);
212 double xcom = (xp0[0] * m0 + (xb0 + xp1[0]) * m1 + (xc0 + xp2[0]) * m2) * invTotalMass;
213 double ycom = (xp0[1] * m0 + (yb0 + xp1[1]) * m1 + (yc0 + xp2[1]) * m2) * invTotalMass;
214 double zcom = (xp0[2] * m0 + (zb0 + xp1[2]) * m1 + (zc0 + xp2[2]) * m2) * invTotalMass;
215
216 double xa1 = xp0[0] - xcom;
217 double ya1 = xp0[1] - ycom;
218 double za1 = xp0[2] - zcom;
219 double xb1 = xb0 + xp1[0] - xcom;
220 double yb1 = yb0 + xp1[1] - ycom;
221 double zb1 = zb0 + xp1[2] - zcom;
222 double xc1 = xc0 + xp2[0] - xcom;
223 double yc1 = yc0 + xp2[1] - ycom;
224 double zc1 = zc0 + xp2[2] - zcom;
225
226 double xaksZd = yb0 * zc0 - zb0 * yc0;
227 double yaksZd = zb0 * xc0 - xb0 * zc0;
228 double zaksZd = xb0 * yc0 - yb0 * xc0;
229 double xaksXd = ya1 * zaksZd - za1 * yaksZd;
230 double yaksXd = za1 * xaksZd - xa1 * zaksZd;
231 double zaksXd = xa1 * yaksZd - ya1 * xaksZd;
232 double xaksYd = yaksZd * zaksXd - zaksZd * yaksXd;
233 double yaksYd = zaksZd * xaksXd - xaksZd * zaksXd;
234 double zaksYd = xaksZd * yaksXd - yaksZd * xaksXd;
235
236 double axlng = sqrt(xaksXd * xaksXd + yaksXd * yaksXd + zaksXd * zaksXd);
237 double aylng = sqrt(xaksYd * xaksYd + yaksYd * yaksYd + zaksYd * zaksYd);
238 double azlng = sqrt(xaksZd * xaksZd + yaksZd * yaksZd + zaksZd * zaksZd);
239 double trns11 = xaksXd / axlng;
240 double trns21 = yaksXd / axlng;
241 double trns31 = zaksXd / axlng;
242 double trns12 = xaksYd / aylng;
243 double trns22 = yaksYd / aylng;
244 double trns32 = zaksYd / aylng;
245 double trns13 = xaksZd / azlng;
246 double trns23 = yaksZd / azlng;
247 double trns33 = zaksZd / azlng;
248
249 double xb0d = trns11 * xb0 + trns21 * yb0 + trns31 * zb0;
250 double yb0d = trns12 * xb0 + trns22 * yb0 + trns32 * zb0;
251 double xc0d = trns11 * xc0 + trns21 * yc0 + trns31 * zc0;
252 double yc0d = trns12 * xc0 + trns22 * yc0 + trns32 * zc0;
253 double za1d = trns13 * xa1 + trns23 * ya1 + trns33 * za1;
254 double xb1d = trns11 * xb1 + trns21 * yb1 + trns31 * zb1;
255 double yb1d = trns12 * xb1 + trns22 * yb1 + trns32 * zb1;
256 double zb1d = trns13 * xb1 + trns23 * yb1 + trns33 * zb1;
257 double xc1d = trns11 * xc1 + trns21 * yc1 + trns31 * zc1;
258 double yc1d = trns12 * xc1 + trns22 * yc1 + trns32 * zc1;
259 double zc1d = trns13 * xc1 + trns23 * yc1 + trns33 * zc1;
260
261
262
263 double rc = 0.5 * distance2;
264 double rb = sqrt(distance1 * distance1 - rc * rc);
265 double ra = rb * (m1 + m2) * invTotalMass;
266 rb -= ra;
267 double sinphi = za1d / ra;
268 double cosphi = sqrt(1 - sinphi * sinphi);
269 double sinpsi = (zb1d - zc1d) / (2 * rc * cosphi);
270 double cospsi = sqrt(1 - sinpsi * sinpsi);
271
272 double ya2d = ra * cosphi;
273 double xb2d = -rc * cospsi;
274 double yb2d = -rb * cosphi - rc * sinpsi * sinphi;
275 double yc2d = -rb * cosphi + rc * sinpsi * sinphi;
276 double xb2d2 = xb2d * xb2d;
277 double hh2 = 4.0f * xb2d2 + (yb2d - yc2d) * (yb2d - yc2d) + (zb1d - zc1d) * (zb1d - zc1d);
278 double deltx = 2.0f * xb2d + sqrt(4.0f * xb2d2 - hh2 + distance2 * distance2);
279 xb2d -= deltx * 0.5;
280
281
282
283 double alpha = (xb2d * (xb0d - xc0d) + yb0d * yb2d + yc0d * yc2d);
284 double beta = (xb2d * (yc0d - yb0d) + xb0d * yb2d + xc0d * yc2d);
285 double gamma = xb0d * yb1d - xb1d * yb0d + xc0d * yc1d - xc1d * yc0d;
286
287 double al2be2 = alpha * alpha + beta * beta;
288 double sintheta = (alpha * gamma - beta * sqrt(al2be2 - gamma * gamma)) / al2be2;
289
290
291
292 double costheta = sqrt(1 - sintheta * sintheta);
293 double xa3d = -ya2d * sintheta;
294 double ya3d = ya2d * costheta;
295 double za3d = za1d;
296 double xb3d = xb2d * costheta - yb2d * sintheta;
297 double yb3d = xb2d * sintheta + yb2d * costheta;
298 double zb3d = zb1d;
299 double xc3d = -xb2d * costheta - yc2d * sintheta;
300 double yc3d = -xb2d * sintheta + yc2d * costheta;
301 double zc3d = zc1d;
302
303
304
305 double xa3 = trns11 * xa3d + trns12 * ya3d + trns13 * za3d;
306 double ya3 = trns21 * xa3d + trns22 * ya3d + trns23 * za3d;
307 double za3 = trns31 * xa3d + trns32 * ya3d + trns33 * za3d;
308 double xb3 = trns11 * xb3d + trns12 * yb3d + trns13 * zb3d;
309 double yb3 = trns21 * xb3d + trns22 * yb3d + trns23 * zb3d;
310 double zb3 = trns31 * xb3d + trns32 * yb3d + trns33 * zb3d;
311 double xc3 = trns11 * xc3d + trns12 * yc3d + trns13 * zc3d;
312 double yc3 = trns21 * xc3d + trns22 * yc3d + trns23 * zc3d;
313 double zc3 = trns31 * xc3d + trns32 * yc3d + trns33 * zc3d;
314
315 xp0[0] = xcom + xa3;
316 xp0[1] = ycom + ya3;
317 xp0[2] = zcom + za3;
318 xp1[0] = xcom + xb3 - xb0;
319 xp1[1] = ycom + yb3 - yb0;
320 xp1[2] = zcom + zb3 - zb0;
321 xp2[0] = xcom + xc3 - xc0;
322 xp2[1] = ycom + yc3 - yc0;
323 xp2[2] = zcom + zc3 - zc0;
324
325 for (int i = 0; i < 3; i++) {
326 xNew[xi0 + i] = xp0[i] + apos0[i];
327 xNew[xi1 + i] = xp1[i] + apos1[i];
328 xNew[xi2 + i] = xp2[i] + apos2[i];
329 }
330 }
331
332 @Override
333 public void applyConstraintToVelocities(
334 final double[] x, double[] v, final double[] masses, double tol) {
335
336
337
338
339 int xi0 = 3 * index0;
340 int xi1 = 3 * index1;
341 int xi2 = 3 * index2;
342
343
344 double[] apos0 = new double[3];
345 double[] apos1 = new double[3];
346 double[] apos2 = new double[3];
347
348
349 double[] v0 = new double[3];
350 double[] v1 = new double[3];
351 double[] v2 = new double[3];
352
353 for (int i = 0; i < 3; i++) {
354 apos0[i] = x[xi0 + i];
355 apos1[i] = x[xi1 + i];
356 apos2[i] = x[xi2 + i];
357 }
358
359 for (int i = 0; i < 3; i++) {
360 v0[i] = v[xi0 + i];
361 v1[i] = v[xi1 + i];
362 v2[i] = v[xi2 + i];
363 }
364
365 double mA = masses[xi0];
366 double mB = masses[xi1];
367 double mC = masses[xi2];
368
369 double[] eAB = new double[3];
370 double[] eBC = new double[3];
371 double[] eCA = new double[3];
372 for (int i = 0; i < 3; i++) {
373 eAB[i] = apos1[i] - apos0[i];
374 eBC[i] = apos2[i] - apos1[i];
375 eCA[i] = apos0[i] - apos2[i];
376 }
377 normalize(eAB, eAB);
378 normalize(eBC, eBC);
379 normalize(eCA, eCA);
380
381
382
383 double vAB = (v1[0] - v0[0]) * eAB[0] + (v1[1] - v0[1]) * eAB[1] + (v1[2] - v0[2]) * eAB[2];
384 double vBC = (v2[0] - v1[0]) * eBC[0] + (v2[1] - v1[1]) * eBC[1] + (v2[2] - v1[2]) * eBC[2];
385 double vCA = (v0[0] - v2[0]) * eCA[0] + (v0[1] - v2[1]) * eCA[1] + (v0[2] - v2[2]) * eCA[2];
386 double cA = -(eAB[0] * eCA[0] + eAB[1] * eCA[1] + eAB[2] * eCA[2]);
387 double cB = -(eAB[0] * eBC[0] + eAB[1] * eBC[1] + eAB[2] * eBC[2]);
388 double cC = -(eBC[0] * eCA[0] + eBC[1] * eCA[1] + eBC[2] * eCA[2]);
389 double s2A = 1 - cA * cA;
390 double s2B = 1 - cB * cB;
391 double s2C = 1 - cC * cC;
392
393
394
395
396
397
398
399 double mABCinv = 1 / (mA * mB * mC);
400 double denom =
401 (((s2A * mB + s2B * mA) * mC
402 + (s2A * mB * mB + 2 * (cA * cB * cC + 1) * mA * mB + s2B * mA * mA))
403 * mC
404 + s2C * mA * mB * (mA + mB))
405 * mABCinv;
406 double tab =
407 ((cB * cC * mA - cA * mB - cA * mC) * vCA
408 + (cA * cC * mB - cB * mC - cB * mA) * vBC
409 + (s2C * mA * mA * mB * mB * mABCinv + (mA + mB + mC)) * vAB)
410 / denom;
411 double tbc =
412 ((cA * cB * mC - cC * mB - cC * mA) * vCA
413 + (s2A * mB * mB * mC * mC * mABCinv + (mA + mB + mC)) * vBC
414 + (cA * cC * mB - cB * mA - cB * mC) * vAB)
415 / denom;
416 double tca =
417 ((s2B * mA * mA * mC * mC * mABCinv + (mA + mB + mC)) * vCA
418 + (cA * cB * mC - cC * mB - cC * mA) * vBC
419 + (cB * cC * mA - cA * mB - cA * mC) * vAB)
420 / denom;
421
422 double invMA = 1.0 / mA;
423 double invMB = 1.0 / mB;
424 double invMC = 1.0 / mC;
425 for (int i = 0; i < 3; i++) {
426 v0[i] += (eAB[i] * tab - eCA[i] * tca) * invMA;
427 v1[i] += (eBC[i] * tbc - eAB[i] * tab) * invMB;
428 v2[i] += (eCA[i] * tca - eBC[i] * tbc) * invMC;
429 }
430
431
432
433
434 arraycopy(v0, 0, v, xi0, 3);
435 arraycopy(v1, 0, v, xi1, 3);
436 arraycopy(v2, 0, v, xi2, 3);
437
438
439
440 }
441
442 @Override
443 public int[] constrainedAtomIndices() {
444 return new int[] {index0, index1, index2};
445 }
446
447 @Override
448 public boolean constraintSatisfied(double[] x, double tol) {
449 return constraintSatisfied(x, null, tol, 0.0);
450 }
451
452 @Override
453 public boolean constraintSatisfied(double[] x, double[] v, double xTol, double vTol) {
454 int xi0 = 3 * index0;
455 int xi1 = 3 * index1;
456 int xi2 = 3 * index2;
457
458
459 double dist01 = 0;
460 double dist02 = 0;
461
462 double dist12 = 0;
463
464 double[] x0 = new double[3];
465 double[] x1 = new double[3];
466 double[] x2 = new double[3];
467 arraycopy(x, xi0, x0, 0, 3);
468 arraycopy(x, xi1, x1, 0, 3);
469 arraycopy(x, xi2, x2, 0, 3);
470
471 for (int i = 0; i < 3; i++) {
472
473 double dx = x0[i] - x1[i];
474 dx *= dx;
475 dist01 += dx;
476
477
478 dx = x0[i] - x2[i];
479 dx *= dx;
480 dist02 += dx;
481
482
483 dx = x1[i] - x2[i];
484 dx *= dx;
485 dist12 += dx;
486 }
487 dist01 = sqrt(dist01);
488 dist02 = sqrt(dist02);
489 dist12 = sqrt(dist12);
490
491
492 double deltaIdeal = Math.abs((dist01 - distance1) / distance1);
493 if (deltaIdeal > xTol) {
494 logger.finer(" delId 01: " + deltaIdeal);
495 return false;
496 }
497 deltaIdeal = Math.abs((dist02 - distance1) / distance1);
498 if (deltaIdeal > xTol) {
499 logger.finer(" delId 02: " + deltaIdeal);
500 return false;
501 }
502 deltaIdeal = Math.abs((dist12 - distance2) / distance2);
503 if (deltaIdeal > xTol) {
504 logger.finer(" delId 12: " + deltaIdeal);
505 return false;
506 }
507
508 if (v != null && vTol > 0) {
509 double[] v0 = new double[3];
510 double[] v1 = new double[3];
511 double[] v2 = new double[3];
512 arraycopy(v, xi0, v0, 0, 3);
513 arraycopy(v, xi1, v1, 0, 3);
514 arraycopy(v, xi2, v2, 0, 3);
515
516
517 double[] v01 = new double[3];
518 double[] v02 = new double[3];
519 double[] v12 = new double[3];
520 sub(v1, v0, v01);
521 sub(v2, v0, v02);
522 sub(v2, v1, v12);
523
524
525 double[] x01 = new double[3];
526 double[] x02 = new double[3];
527 double[] x12 = new double[3];
528 sub(x1, x0, x01);
529 sub(x2, x0, x02);
530 sub(x2, x1, x12);
531
532 double xv01 = dot(v01, x01);
533 double xv02 = dot(v02, x02);
534 double xv12 = dot(v12, x12);
535
536 if (abs(xv01) > vTol) {
537 return false;
538 }
539 if (abs(xv02) > vTol) {
540 return false;
541 }
542 if (abs(xv12) > vTol) {
543 return false;
544 }
545 }
546 return true;
547 }
548
549 @Override
550 public int getNumDegreesFrozen() {
551 return 3;
552
553 }
554 }