1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode:nil; -*- */
2 /* vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 */
3 /*
4 MDAnalysis --- http://mdanalysis.googlecode.com
5
6 Copyright (c) 2006-2014 Naveen Michaud-Agrawal,
7 Elizabeth J. Denning, Oliver Beckstein,
8 and contributors (see AUTHORS for the full list)
9 Released under the GNU Public Licence, v2 or any higher version
10
11 Please cite your use of MDAnalysis in published work:
12
13 N. Michaud-Agrawal, E. J. Denning, T. B. Woolf, and
14 O. Beckstein. MDAnalysis: A Toolkit for the Analysis of
15 Molecular Dynamics Simulations. J. Comput. Chem. 32 (2011), 2319--2327,
16 in press.
17 */
18
19 #ifndef __DISTANCES_H
20 #define __DISTANCES_H
21
22 #include <math.h>
23
24 #include <float.h>
25 typedef float coordinate[3];
26
27 #ifdef PARALLEL
28 #include <omp.h>
29 #define USED_OPENMP 1
30 #else
31 #define USED_OPENMP 0
32 #endif
33
minimum_image(double * x,float * box,float * inverse_box)34 static void minimum_image(double *x, float *box, float *inverse_box)
35 {
36 int i;
37 double s;
38 for (i=0; i<3; i++) {
39 if (box[i] > FLT_EPSILON) {
40 s = inverse_box[i] * x[i];
41 x[i] = box[i] * (s - round(s));
42 }
43 }
44 }
45
minimum_image_triclinic(double * dx,coordinate * box)46 static void minimum_image_triclinic(double *dx, coordinate* box)
47 {
48 // Minimum image convention for triclinic systems, modelled after domain.cpp in LAMMPS
49 // Assumes that there is a maximum separation of 1 box length (enforced in dist functions
50 // by moving all particles to inside the box before calculating separations)
51 // Requires a box
52 // Assumes box having zero values for box[0][1], box[0][2] and box [1][2]
53 double dmin[3], rx[3], ry[3], rz[3];
54 double min = FLT_MAX, d;
55 int i, x, y, z;
56
57 for (x = -1; x < 2; ++x) {
58 rx[0] = dx[0] + box[0][0] * (float)x;
59 rx[1] = dx[1];
60 rx[2] = dx[2];
61 for (y = -1; y < 2; ++y) {
62 ry[0] = rx[0] + box[1][0] * (float)y;
63 ry[1] = rx[1] + box[1][1] * (float)y;
64 ry[2] = rx[2];
65 for (z = -1; z < 2; ++z) {
66 rz[0] = ry[0] + box[2][0] * (float)z;
67 rz[1] = ry[1] + box[2][1] * (float)z;
68 rz[2] = ry[2] + box[2][2] * (float)z;
69 d = rz[0]*rz[0] + rz[1]*rz[1] + rz[2] * rz[2];
70 if (d < min) {
71 for (i=0; i<3; ++i){
72 min = d;
73 dmin[i] = rz[i];
74 }
75 }
76 }
77 }
78 }
79 for (i =0; i<3; ++i) {
80 dx[i] = dmin[i];
81 }
82 }
83
_ortho_pbc(coordinate * coords,int numcoords,float * box,float * box_inverse)84 static void _ortho_pbc(coordinate* coords, int numcoords, float* box, float* box_inverse)
85 {
86 int i, s[3];
87 // Moves all coordinates to within the box boundaries for a orthogonal box
88 #ifdef PARALLEL
89 #pragma omp parallel for private(i, s) shared(coords)
90 #endif
91 for (i=0; i < numcoords; i++){
92 s[0] = floor(coords[i][0] * box_inverse[0]);
93 s[1] = floor(coords[i][1] * box_inverse[1]);
94 s[2] = floor(coords[i][2] * box_inverse[2]);
95 coords[i][0] -= s[0] * box[0];
96 coords[i][1] -= s[1] * box[1];
97 coords[i][2] -= s[2] * box[2];
98 }
99 }
100
_triclinic_pbc(coordinate * coords,int numcoords,coordinate * box,float * box_inverse)101 static void _triclinic_pbc(coordinate* coords, int numcoords, coordinate* box, float* box_inverse)
102 {
103 int i, s;
104 // Inverse of matrix box (here called "m")
105 // [ 1/m00 , 0 , 0 ]
106 // [ -m10/(m00*m11) , 1/m11 , 0 ]
107 // [(m10*m21/(m00*m11) - m20/m00)/m22, -m21/(m11*m22), 1/m22]
108 float bi00 = box_inverse[0];
109 float bi11 = box_inverse[1];
110 float bi22 = box_inverse[2];
111 float bi01 = -box[1][0]*bi00*bi11;
112 float bi02 = (box[1][0]*box[2][1]*bi11 - box[2][0])*bi00*bi22;
113 float bi12 = -box[2][1]*bi11*bi22;
114 // Moves all coordinates to within the box boundaries for a triclinic box
115 // Assumes box having zero values for box[0][1], box[0][2] and box [1][2]
116 #ifdef PARALLEL
117 #pragma omp parallel for private(i, s) shared(coords)
118 #endif
119 for (i=0; i < numcoords; i++){
120 // translate coords[i] to central cell along c-axis
121 s = floor(coords[i][2]*bi22);
122 coords[i][2] -= s * box[2][2];
123 coords[i][1] -= s * box[2][1];
124 coords[i][0] -= s * box[2][0];
125 // translate remainder of coords[i] to central cell along b-axis
126 s = floor(coords[i][1]*bi11 + coords[i][2]*bi12);
127 coords[i][1] -= s * box[1][1];
128 coords[i][0] -= s * box[1][0];
129 // translate remainder of coords[i] to central cell along a-axis
130 s = floor(coords[i][0]*bi00 + coords[i][1]*bi01 + coords[i][2]*bi02);
131 coords[i][0] -= s * box[0][0];
132 }
133 }
134
_calc_distance_array(coordinate * ref,int numref,coordinate * conf,int numconf,double * distances)135 static void _calc_distance_array(coordinate* ref, int numref, coordinate* conf,
136 int numconf, double* distances)
137 {
138 int i, j;
139 double dx[3];
140 double rsq;
141
142 #ifdef PARALLEL
143 #pragma omp parallel for private(i, j, dx, rsq) shared(distances)
144 #endif
145 for (i=0; i<numref; i++) {
146 for (j=0; j<numconf; j++) {
147 dx[0] = conf[j][0] - ref[i][0];
148 dx[1] = conf[j][1] - ref[i][1];
149 dx[2] = conf[j][2] - ref[i][2];
150 rsq = (dx[0]*dx[0]) + (dx[1]*dx[1]) + (dx[2]*dx[2]);
151 *(distances+i*numconf+j) = sqrt(rsq);
152 }
153 }
154 }
155
_calc_distance_array_ortho(coordinate * ref,int numref,coordinate * conf,int numconf,float * box,double * distances)156 static void _calc_distance_array_ortho(coordinate* ref, int numref, coordinate* conf,
157 int numconf, float* box, double* distances)
158 {
159 int i, j;
160 double dx[3];
161 float inverse_box[3];
162 double rsq;
163
164 inverse_box[0] = 1.0 / box[0];
165 inverse_box[1] = 1.0 / box[1];
166 inverse_box[2] = 1.0 / box[2];
167 #ifdef PARALLEL
168 #pragma omp parallel for private(i, j, dx, rsq) shared(distances)
169 #endif
170 for (i=0; i<numref; i++) {
171 for (j=0; j<numconf; j++) {
172 dx[0] = conf[j][0] - ref[i][0];
173 dx[1] = conf[j][1] - ref[i][1];
174 dx[2] = conf[j][2] - ref[i][2];
175 // Periodic boundaries
176 minimum_image(dx, box, inverse_box);
177 rsq = (dx[0]*dx[0]) + (dx[1]*dx[1]) + (dx[2]*dx[2]);
178 *(distances+i*numconf+j) = sqrt(rsq);
179 }
180 }
181 }
182
_calc_distance_array_triclinic(coordinate * ref,int numref,coordinate * conf,int numconf,coordinate * box,double * distances)183 static void _calc_distance_array_triclinic(coordinate* ref, int numref,
184 coordinate* conf, int numconf,
185 coordinate* box, double* distances)
186 {
187 int i, j;
188 double dx[3];
189 float box_inverse[3];
190 double rsq;
191
192 box_inverse[0] = 1.0 / box[0][0];
193 box_inverse[1] = 1.0 / box[1][1];
194 box_inverse[2] = 1.0 / box[2][2];
195 // Move coords to inside box
196 _triclinic_pbc(ref, numref, box, box_inverse);
197 _triclinic_pbc(conf, numconf, box, box_inverse);
198
199 #ifdef PARALLEL
200 #pragma omp parallel for private(i, j, dx, rsq) shared(distances)
201 #endif
202 for (i=0; i<numref; i++){
203 for (j=0; j<numconf; j++){
204 dx[0] = conf[j][0] - ref[i][0];
205 dx[1] = conf[j][1] - ref[i][1];
206 dx[2] = conf[j][2] - ref[i][2];
207 minimum_image_triclinic(dx, box);
208 rsq = (dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]);
209 *(distances + i*numconf + j) = sqrt(rsq);
210 }
211 }
212 }
213
_calc_self_distance_array(coordinate * ref,int numref,double * distances,int distnum)214 static void _calc_self_distance_array(coordinate* ref, int numref, double* distances,
215 int distnum)
216 {
217 int i, j, distpos;
218 double dx[3];
219 double rsq;
220
221 distpos = 0;
222
223 #ifdef PARALLEL
224 #pragma omp parallel for private(i, distpos, j, dx, rsq) shared(distances)
225 #endif
226 for (i=0; i<numref; i++) {
227 #ifdef PARALLEL
228 distpos = i * (2 * numref - i - 1) / 2; // calculates the offset into distances
229 #endif
230 for (j=i+1; j<numref; j++) {
231 dx[0] = ref[j][0] - ref[i][0];
232 dx[1] = ref[j][1] - ref[i][1];
233 dx[2] = ref[j][2] - ref[i][2];
234 rsq = (dx[0]*dx[0]) + (dx[1]*dx[1]) + (dx[2]*dx[2]);
235 *(distances+distpos) = sqrt(rsq);
236 distpos += 1;
237 }
238 }
239 }
240
_calc_self_distance_array_ortho(coordinate * ref,int numref,float * box,double * distances,int distnum)241 static void _calc_self_distance_array_ortho(coordinate* ref, int numref, float* box,
242 double* distances, int distnum)
243 {
244 int i, j, distpos;
245 double dx[3];
246 float inverse_box[3];
247 double rsq;
248
249 inverse_box[0] = 1.0 / box[0];
250 inverse_box[1] = 1.0 / box[1];
251 inverse_box[2] = 1.0 / box[2];
252 distpos = 0;
253
254 #ifdef PARALLEL
255 #pragma omp parallel for private(i, distpos, j, dx, rsq) shared(distances)
256 #endif
257 for (i=0; i<numref; i++) {
258 #ifdef PARALLEL
259 distpos = i * (2 * numref - i - 1) / 2; // calculates the offset into distances
260 #endif
261 for (j=i+1; j<numref; j++) {
262 dx[0] = ref[j][0] - ref[i][0];
263 dx[1] = ref[j][1] - ref[i][1];
264 dx[2] = ref[j][2] - ref[i][2];
265 // Periodic boundaries
266 minimum_image(dx, box, inverse_box);
267 rsq = (dx[0]*dx[0]) + (dx[1]*dx[1]) + (dx[2]*dx[2]);
268 *(distances+distpos) = sqrt(rsq);
269 distpos += 1;
270 }
271 }
272 }
273
_calc_self_distance_array_triclinic(coordinate * ref,int numref,coordinate * box,double * distances,int distnum)274 static void _calc_self_distance_array_triclinic(coordinate* ref, int numref,
275 coordinate* box, double *distances,
276 int distnum)
277 {
278 int i, j, distpos;
279 double dx[3];
280 double rsq;
281 float box_inverse[3];
282
283 box_inverse[0] = 1.0 / box[0][0];
284 box_inverse[1] = 1.0 / box[1][1];
285 box_inverse[2] = 1.0 / box[2][2];
286
287 _triclinic_pbc(ref, numref, box, box_inverse);
288
289 distpos = 0;
290
291 #ifdef PARALLEL
292 #pragma omp parallel for private(i, distpos, j, dx, rsq) shared(distances)
293 #endif
294 for (i=0; i<numref; i++){
295 #ifdef PARALLEL
296 distpos = i * (2 * numref - i - 1) / 2; // calculates the offset into distances
297 #endif
298 for (j=i+1; j<numref; j++){
299 dx[0] = ref[j][0] - ref[i][0];
300 dx[1] = ref[j][1] - ref[i][1];
301 dx[2] = ref[j][2] - ref[i][2];
302 minimum_image_triclinic(dx, box);
303 rsq = (dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2]);
304 *(distances + distpos) = sqrt(rsq);
305 distpos += 1;
306 }
307 }
308 }
309
_coord_transform(float coords[][3],int numCoords,float box[][3])310 void _coord_transform(float coords[][3], int numCoords, float box[][3])
311 {
312 int i, j, k;
313 float newpos[3];
314 // Matrix multiplication inCoords * box = outCoords
315 // Multiplication done in place using temp array 'new'
316 // Used to transform coordinates to/from S/R space in trilinic boxes
317 #ifdef PARALLEL
318 #pragma omp parallel for private(i, j, k, newpos) shared(coords)
319 #endif
320 for (i=0; i < numCoords; i++){
321 newpos[0] = 0.0;
322 newpos[1] = 0.0;
323 newpos[2] = 0.0;
324 for (j=0; j<3; j++){
325 for (k=0; k<3; k++){
326 newpos[j] += coords[i][k] * box[k][j];
327 }
328 }
329 coords[i][0] = newpos[0];
330 coords[i][1] = newpos[1];
331 coords[i][2] = newpos[2];
332 }
333 }
334
_calc_bond_distance(coordinate * atom1,coordinate * atom2,int numatom,double * distances)335 static void _calc_bond_distance(coordinate* atom1, coordinate* atom2,
336 int numatom, double* distances)
337 {
338 int i;
339 double dx[3];
340 double rsq;
341
342 #ifdef PARALLEL
343 #pragma omp parallel for private(i, dx, rsq) shared(distances)
344 #endif
345 for (i=0; i<numatom; i++) {
346 dx[0] = atom1[i][0] - atom2[i][0];
347 dx[1] = atom1[i][1] - atom2[i][1];
348 dx[2] = atom1[i][2] - atom2[i][2];
349 rsq = (dx[0]*dx[0])+(dx[1]*dx[1])+(dx[2]*dx[2]);
350 *(distances+i) = sqrt(rsq);
351 }
352 }
353
_calc_bond_distance_ortho(coordinate * atom1,coordinate * atom2,int numatom,float * box,double * distances)354 static void _calc_bond_distance_ortho(coordinate* atom1, coordinate* atom2,
355 int numatom, float* box, double* distances)
356 {
357 int i;
358 double dx[3];
359 float inverse_box[3];
360 double rsq;
361
362 inverse_box[0] = 1.0/box[0];
363 inverse_box[1] = 1.0/box[1];
364 inverse_box[2] = 1.0/box[2];
365
366 #ifdef PARALLEL
367 #pragma omp parallel for private(i, dx, rsq) shared(distances)
368 #endif
369 for (i=0; i<numatom; i++) {
370 dx[0] = atom1[i][0] - atom2[i][0];
371 dx[1] = atom1[i][1] - atom2[i][1];
372 dx[2] = atom1[i][2] - atom2[i][2];
373 // PBC time!
374 minimum_image(dx, box, inverse_box);
375 rsq = (dx[0]*dx[0])+(dx[1]*dx[1])+(dx[2]*dx[2]);
376 *(distances+i) = sqrt(rsq);
377 }
378 }
_calc_bond_distance_triclinic(coordinate * atom1,coordinate * atom2,int numatom,coordinate * box,double * distances)379 static void _calc_bond_distance_triclinic(coordinate* atom1, coordinate* atom2,
380 int numatom, coordinate* box,
381 double* distances)
382 {
383 int i;
384 double dx[3];
385 float box_inverse[3];
386 double rsq;
387
388 box_inverse[0] = 1.0/box[0][0];
389 box_inverse[1] = 1.0/box[1][1];
390 box_inverse[2] = 1.0/box[2][2];
391
392 _triclinic_pbc(atom1, numatom, box, box_inverse);
393 _triclinic_pbc(atom2, numatom, box, box_inverse);
394
395 #ifdef PARALLEL
396 #pragma omp parallel for private(i, dx, rsq) shared(distances)
397 #endif
398 for (i=0; i<numatom; i++) {
399 dx[0] = atom1[i][0] - atom2[i][0];
400 dx[1] = atom1[i][1] - atom2[i][1];
401 dx[2] = atom1[i][2] - atom2[i][2];
402 // PBC time!
403 minimum_image_triclinic(dx, box);
404 rsq = (dx[0]*dx[0])+(dx[1]*dx[1])+(dx[2]*dx[2]);
405 *(distances+i) = sqrt(rsq);
406 }
407 }
408
_calc_angle(coordinate * atom1,coordinate * atom2,coordinate * atom3,int numatom,double * angles)409 static void _calc_angle(coordinate* atom1, coordinate* atom2,
410 coordinate* atom3, int numatom, double* angles)
411 {
412 int i;
413 double rji[3], rjk[3];
414 double x, y, xp[3];
415
416 #ifdef PARALLEL
417 #pragma omp parallel for private(i, rji, rjk, x, xp, y) shared(angles)
418 #endif
419 for (i=0; i<numatom; i++) {
420 rji[0] = atom1[i][0] - atom2[i][0];
421 rji[1] = atom1[i][1] - atom2[i][1];
422 rji[2] = atom1[i][2] - atom2[i][2];
423
424 rjk[0] = atom3[i][0] - atom2[i][0];
425 rjk[1] = atom3[i][1] - atom2[i][1];
426 rjk[2] = atom3[i][2] - atom2[i][2];
427
428 x = rji[0]*rjk[0] + rji[1]*rjk[1] + rji[2]*rjk[2];
429
430 xp[0] = rji[1]*rjk[2] - rji[2]*rjk[1];
431 xp[1] =-rji[0]*rjk[2] + rji[2]*rjk[0];
432 xp[2] = rji[0]*rjk[1] - rji[1]*rjk[0];
433
434 y = sqrt(xp[0]*xp[0] + xp[1]*xp[1] + xp[2]*xp[2]);
435
436 *(angles+i) = atan2(y,x);
437 }
438 }
439
_calc_angle_ortho(coordinate * atom1,coordinate * atom2,coordinate * atom3,int numatom,float * box,double * angles)440 static void _calc_angle_ortho(coordinate* atom1, coordinate* atom2,
441 coordinate* atom3, int numatom,
442 float* box, double* angles)
443 {
444 // Angle is calculated between two vectors
445 // pbc option ensures that vectors are constructed between atoms in the same image as eachother
446 // ie that vectors don't go across a boxlength
447 // it doesn't matter if vectors are from different boxes however
448 int i;
449 double rji[3], rjk[3];
450 double x, y, xp[3];
451 float inverse_box[3];
452
453 inverse_box[0] = 1.0/box[0];
454 inverse_box[1] = 1.0/box[1];
455 inverse_box[2] = 1.0/box[2];
456
457 #ifdef PARALLEL
458 #pragma omp parallel for private(i, rji, rjk, x, xp, y) shared(angles)
459 #endif
460 for (i=0; i<numatom; i++) {
461 rji[0] = atom1[i][0] - atom2[i][0];
462 rji[1] = atom1[i][1] - atom2[i][1];
463 rji[2] = atom1[i][2] - atom2[i][2];
464 minimum_image(rji, box, inverse_box);
465
466 rjk[0] = atom3[i][0] - atom2[i][0];
467 rjk[1] = atom3[i][1] - atom2[i][1];
468 rjk[2] = atom3[i][2] - atom2[i][2];
469 minimum_image(rjk, box, inverse_box);
470
471 x = rji[0]*rjk[0] + rji[1]*rjk[1] + rji[2]*rjk[2];
472
473 xp[0] = rji[1]*rjk[2] - rji[2]*rjk[1];
474 xp[1] =-rji[0]*rjk[2] + rji[2]*rjk[0];
475 xp[2] = rji[0]*rjk[1] - rji[1]*rjk[0];
476
477 y = sqrt(xp[0]*xp[0] + xp[1]*xp[1] + xp[2]*xp[2]);
478
479 *(angles+i) = atan2(y,x);
480 }
481 }
482
_calc_angle_triclinic(coordinate * atom1,coordinate * atom2,coordinate * atom3,int numatom,coordinate * box,double * angles)483 static void _calc_angle_triclinic(coordinate* atom1, coordinate* atom2,
484 coordinate* atom3, int numatom,
485 coordinate* box, double* angles)
486 {
487 // Triclinic version of min image aware angle calculate, see above
488 int i;
489 double rji[3], rjk[3];
490 double x, y, xp[3];
491 float box_inverse[3];
492
493 box_inverse[0] = 1.0/box[0][0];
494 box_inverse[1] = 1.0/box[1][1];
495 box_inverse[2] = 1.0/box[2][2];
496
497 _triclinic_pbc(atom1, numatom, box, box_inverse);
498 _triclinic_pbc(atom2, numatom, box, box_inverse);
499 _triclinic_pbc(atom3, numatom, box, box_inverse);
500
501 #ifdef PARALLEL
502 #pragma omp parallel for private(i, rji, rjk, x, xp, y) shared(angles)
503 #endif
504 for (i=0; i<numatom; i++) {
505 rji[0] = atom1[i][0] - atom2[i][0];
506 rji[1] = atom1[i][1] - atom2[i][1];
507 rji[2] = atom1[i][2] - atom2[i][2];
508 minimum_image_triclinic(rji, box);
509
510 rjk[0] = atom3[i][0] - atom2[i][0];
511 rjk[1] = atom3[i][1] - atom2[i][1];
512 rjk[2] = atom3[i][2] - atom2[i][2];
513 minimum_image_triclinic(rjk, box);
514
515 x = rji[0]*rjk[0] + rji[1]*rjk[1] + rji[2]*rjk[2];
516
517 xp[0] = rji[1]*rjk[2] - rji[2]*rjk[1];
518 xp[1] =-rji[0]*rjk[2] + rji[2]*rjk[0];
519 xp[2] = rji[0]*rjk[1] - rji[1]*rjk[0];
520
521 y = sqrt(xp[0]*xp[0] + xp[1]*xp[1] + xp[2]*xp[2]);
522
523 *(angles+i) = atan2(y,x);
524 }
525 }
526
_calc_dihedral_angle(double * va,double * vb,double * vc,double * result)527 static void _calc_dihedral_angle(double* va, double* vb, double* vc, double* result)
528 {
529 // Returns atan2 from vectors va, vb, vc
530 double n1[3], n2[3];
531 double xp[3], vb_norm;
532 double x, y;
533
534 //n1 is normal vector to -va, vb
535 //n2 is normal vector to -vb, vc
536 n1[0] =-va[1]*vb[2] + va[2]*vb[1];
537 n1[1] = va[0]*vb[2] - va[2]*vb[0];
538 n1[2] =-va[0]*vb[1] + va[1]*vb[0];
539
540 n2[0] =-vb[1]*vc[2] + vb[2]*vc[1];
541 n2[1] = vb[0]*vc[2] - vb[2]*vc[0];
542 n2[2] =-vb[0]*vc[1] + vb[1]*vc[0];
543
544 // x = dot(n1,n2) = cos theta
545 x = (n1[0]*n2[0] + n1[1]*n2[1] + n1[2]*n2[2]);
546
547 // xp = cross(n1,n2)
548 xp[0] = n1[1]*n2[2] - n1[2]*n2[1];
549 xp[1] =-n1[0]*n2[2] + n1[2]*n2[0];
550 xp[2] = n1[0]*n2[1] - n1[1]*n2[0];
551
552 vb_norm = sqrt(vb[0]*vb[0] + vb[1]*vb[1] + vb[2]*vb[2]);
553
554 y = (xp[0]*vb[0] + xp[1]*vb[1] + xp[2]*vb[2]) / vb_norm;
555
556 if ( (fabs(x) == 0.0) && (fabs(y) == 0.0) ) // numpy consistency
557 {
558 *result = NAN;
559 return;
560 }
561
562 *result = atan2(y, x); //atan2 is better conditioned than acos
563 }
564
_calc_dihedral(coordinate * atom1,coordinate * atom2,coordinate * atom3,coordinate * atom4,int numatom,double * angles)565 static void _calc_dihedral(coordinate* atom1, coordinate* atom2,
566 coordinate* atom3, coordinate* atom4,
567 int numatom, double* angles)
568 {
569 int i;
570 double va[3], vb[3], vc[3];
571
572 #ifdef PARALLEL
573 #pragma omp parallel for private(i, va, vb, vc) shared(angles)
574 #endif
575 for (i=0; i<numatom; i++) {
576 // connecting vectors between all 4 atoms: 1 -va-> 2 -vb-> 3 -vc-> 4
577 va[0] = atom2[i][0] - atom1[i][0];
578 va[1] = atom2[i][1] - atom1[i][1];
579 va[2] = atom2[i][2] - atom1[i][2];
580
581 vb[0] = atom3[i][0] - atom2[i][0];
582 vb[1] = atom3[i][1] - atom2[i][1];
583 vb[2] = atom3[i][2] - atom2[i][2];
584
585 vc[0] = atom4[i][0] - atom3[i][0];
586 vc[1] = atom4[i][1] - atom3[i][1];
587 vc[2] = atom4[i][2] - atom3[i][2];
588
589 _calc_dihedral_angle(va, vb, vc, angles + i);
590 }
591 }
592
_calc_dihedral_ortho(coordinate * atom1,coordinate * atom2,coordinate * atom3,coordinate * atom4,int numatom,float * box,double * angles)593 static void _calc_dihedral_ortho(coordinate* atom1, coordinate* atom2,
594 coordinate* atom3, coordinate* atom4,
595 int numatom, float* box, double* angles)
596 {
597 int i;
598 double va[3], vb[3], vc[3];
599 float inverse_box[3];
600
601 inverse_box[0] = 1.0/box[0];
602 inverse_box[1] = 1.0/box[1];
603 inverse_box[2] = 1.0/box[2];
604
605 #ifdef PARALLEL
606 #pragma omp parallel for private(i, va, vb, vc) shared(angles)
607 #endif
608 for (i=0; i<numatom; i++) {
609 // connecting vectors between all 4 atoms: 1 -va-> 2 -vb-> 3 -vc-> 4
610 va[0] = atom2[i][0] - atom1[i][0];
611 va[1] = atom2[i][1] - atom1[i][1];
612 va[2] = atom2[i][2] - atom1[i][2];
613 minimum_image(va, box, inverse_box);
614
615 vb[0] = atom3[i][0] - atom2[i][0];
616 vb[1] = atom3[i][1] - atom2[i][1];
617 vb[2] = atom3[i][2] - atom2[i][2];
618 minimum_image(vb, box, inverse_box);
619
620 vc[0] = atom4[i][0] - atom3[i][0];
621 vc[1] = atom4[i][1] - atom3[i][1];
622 vc[2] = atom4[i][2] - atom3[i][2];
623 minimum_image(vc, box, inverse_box);
624
625 _calc_dihedral_angle(va, vb, vc, angles + i);
626 }
627 }
628
_calc_dihedral_triclinic(coordinate * atom1,coordinate * atom2,coordinate * atom3,coordinate * atom4,int numatom,coordinate * box,double * angles)629 static void _calc_dihedral_triclinic(coordinate* atom1, coordinate* atom2,
630 coordinate* atom3, coordinate* atom4,
631 int numatom, coordinate* box, double* angles)
632 {
633 int i;
634 double va[3], vb[3], vc[3];
635 float box_inverse[3];
636
637 box_inverse[0] = 1.0/box[0][0];
638 box_inverse[1] = 1.0/box[1][1];
639 box_inverse[2] = 1.0/box[2][2];
640
641 _triclinic_pbc(atom1, numatom, box, box_inverse);
642 _triclinic_pbc(atom2, numatom, box, box_inverse);
643 _triclinic_pbc(atom3, numatom, box, box_inverse);
644 _triclinic_pbc(atom4, numatom, box, box_inverse);
645
646 #ifdef PARALLEL
647 #pragma omp parallel for private(i, va, vb, vc) shared(angles)
648 #endif
649 for (i=0; i<numatom; i++) {
650 // connecting vectors between all 4 atoms: 1 -va-> 2 -vb-> 3 -vc-> 4
651 va[0] = atom2[i][0] - atom1[i][0];
652 va[1] = atom2[i][1] - atom1[i][1];
653 va[2] = atom2[i][2] - atom1[i][2];
654 minimum_image_triclinic(va, box);
655
656 vb[0] = atom3[i][0] - atom2[i][0];
657 vb[1] = atom3[i][1] - atom2[i][1];
658 vb[2] = atom3[i][2] - atom2[i][2];
659 minimum_image_triclinic(vb, box);
660
661 vc[0] = atom4[i][0] - atom3[i][0];
662 vc[1] = atom4[i][1] - atom3[i][1];
663 vc[2] = atom4[i][2] - atom3[i][2];
664 minimum_image_triclinic(vc, box);
665
666 _calc_dihedral_angle(va, vb, vc, angles + i);
667 }
668 }
669 #endif
670