Revised wording in pdb2gmx.c, hopefully clearer now.
[gromacs/rigid-bodies.git] / src / gmxlib / pbc.c
blobaf63fc6d047219aaaae81050ad343c75d115b221
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
3 *
4 * This source code is part of
5 *
6 * G R O M A C S
7 *
8 * GROningen MAchine for Chemical Simulations
9 *
10 * VERSION 3.2.0
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
33 * And Hey:
34 * GROningen Mixture of Alchemy and Childrens' Stories
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
40 #include <math.h>
41 #include "sysstuff.h"
42 #include "typedefs.h"
43 #include "vec.h"
44 #include "maths.h"
45 #include "main.h"
46 #include "pbc.h"
47 #include "smalloc.h"
48 #include "txtdump.h"
49 #include "gmx_fatal.h"
50 #include "names.h"
52 /* Skip 0 so we have more chance of detecting if we forgot to call set_pbc. */
53 enum { epbcdxRECTANGULAR=1, epbcdxTRICLINIC,
54 epbcdx2D_RECT, epbcdx2D_TRIC,
55 epbcdx1D_RECT, epbcdx1D_TRIC,
56 epbcdxSCREW_RECT, epbcdxSCREW_TRIC,
57 epbcdxNOPBC, epbcdxUNSUPPORTED };
59 /* Margin factor for error message and correction if the box is too skewed */
60 #define BOX_MARGIN 1.0010
61 #define BOX_MARGIN_CORRECT 1.0005
63 int ePBC2npbcdim(int ePBC)
65 int npbcdim=0;
67 switch(ePBC) {
68 case epbcXYZ: npbcdim = 3; break;
69 case epbcXY: npbcdim = 2; break;
70 case epbcSCREW: npbcdim = 3; break;
71 case epbcNONE: npbcdim = 0; break;
72 default: gmx_fatal(FARGS,"Unknown ePBC=%d in ePBC2npbcdim",ePBC);
75 return npbcdim;
78 int inputrec2nboundeddim(t_inputrec *ir)
80 if (ir->nwall == 2 && ir->ePBC == epbcXY)
82 return 3;
84 else
86 return ePBC2npbcdim(ir->ePBC);
90 void dump_pbc(FILE *fp,t_pbc *pbc)
92 rvec sum_box;
94 fprintf(fp,"ePBCDX = %d\n",pbc->ePBCDX);
95 pr_rvecs(fp,0,"box",pbc->box,DIM);
96 pr_rvecs(fp,0,"fbox_diag",&pbc->fbox_diag,1);
97 pr_rvecs(fp,0,"hbox_diag",&pbc->hbox_diag,1);
98 pr_rvecs(fp,0,"mhbox_diag",&pbc->mhbox_diag,1);
99 rvec_add(pbc->hbox_diag,pbc->mhbox_diag,sum_box);
100 pr_rvecs(fp,0,"sum of the above two",&sum_box,1);
101 fprintf(fp,"max_cutoff2 = %g\n",pbc->max_cutoff2);
102 fprintf(fp,"bLimitDistance = %s\n",BOOL(pbc->bLimitDistance));
103 fprintf(fp,"limit_distance2 = %g\n",pbc->limit_distance2);
104 fprintf(fp,"ntric_vec = %d\n",pbc->ntric_vec);
105 if (pbc->ntric_vec > 0) {
106 pr_ivecs(fp,0,"tric_shift",pbc->tric_shift,pbc->ntric_vec,FALSE);
107 pr_rvecs(fp,0,"tric_vec",pbc->tric_vec,pbc->ntric_vec);
111 const char *check_box(int ePBC,matrix box)
113 const char *ptr;
115 if (ePBC == -1)
116 ePBC = guess_ePBC(box);
118 if (ePBC == epbcNONE)
119 return NULL;
121 if ((box[XX][YY] != 0) || (box[XX][ZZ] != 0) || (box[YY][ZZ] != 0)) {
122 ptr = "Only triclinic boxes with the first vector parallel to the x-axis and the second vector in the xy-plane are supported.";
123 } else if (ePBC == epbcSCREW && (box[YY][XX] != 0 || box[ZZ][XX] != 0)) {
124 ptr = "The unit cell can not have off-diagonal x-components with screw pbc";
125 } else if (fabs(box[YY][XX]) > BOX_MARGIN*0.5*box[XX][XX] ||
126 (ePBC != epbcXY &&
127 (fabs(box[ZZ][XX]) > BOX_MARGIN*0.5*box[XX][XX] ||
128 fabs(box[ZZ][YY]) > BOX_MARGIN*0.5*box[YY][YY]))) {
129 ptr = "Triclinic box is too skewed.";
130 } else {
131 ptr = NULL;
134 return ptr;
137 real max_cutoff2(int ePBC,matrix box)
139 real min_hv2,min_ss;
141 /* Physical limitation of the cut-off
142 * by half the length of the shortest box vector.
144 min_hv2 = min(0.25*norm2(box[XX]),0.25*norm2(box[YY]));
145 if (ePBC != epbcXY)
146 min_hv2 = min(min_hv2,0.25*norm2(box[ZZ]));
148 /* Limitation to the smallest diagonal element due to optimizations:
149 * checking only linear combinations of single box-vectors (2 in x)
150 * in the grid search and pbc_dx is a lot faster
151 * than checking all possible combinations.
153 if (ePBC == epbcXY) {
154 min_ss = min(box[XX][XX],box[YY][YY]);
155 } else {
156 min_ss = min(box[XX][XX],min(box[YY][YY]-fabs(box[ZZ][YY]),box[ZZ][ZZ]));
159 return min(min_hv2,min_ss*min_ss);
162 /* this one is mostly harmless... */
163 static gmx_bool bWarnedGuess=FALSE;
165 int guess_ePBC(matrix box)
167 int ePBC;
169 if (box[XX][XX]>0 && box[YY][YY]>0 && box[ZZ][ZZ]>0) {
170 ePBC = epbcXYZ;
171 } else if (box[XX][XX]>0 && box[YY][YY]>0 && box[ZZ][ZZ]==0) {
172 ePBC = epbcXY;
173 } else if (box[XX][XX]==0 && box[YY][YY]==0 && box[ZZ][ZZ]==0) {
174 ePBC = epbcNONE;
175 } else {
176 if (!bWarnedGuess) {
177 fprintf(stderr,"WARNING: Unsupported box diagonal %f %f %f, "
178 "will not use periodic boundary conditions\n\n",
179 box[XX][XX],box[YY][YY],box[ZZ][ZZ]);
180 bWarnedGuess = TRUE;
182 ePBC = epbcNONE;
185 if (debug)
186 fprintf(debug,"Guessed pbc = %s from the box matrix\n",epbc_names[ePBC]);
188 return ePBC;
191 static int correct_box_elem(FILE *fplog,int step,tensor box,int v,int d)
193 int shift,maxshift=10;
195 shift = 0;
197 /* correct elem d of vector v with vector d */
198 while (box[v][d] > BOX_MARGIN_CORRECT*0.5*box[d][d]) {
199 if (fplog) {
200 fprintf(fplog,"Step %d: correcting invalid box:\n",step);
201 pr_rvecs(fplog,0,"old box",box,DIM);
203 rvec_dec(box[v],box[d]);
204 shift--;
205 if (fplog) {
206 pr_rvecs(fplog,0,"new box",box,DIM);
208 if (shift <= -maxshift)
209 gmx_fatal(FARGS,
210 "Box was shifted at least %d times. Please see log-file.",
211 maxshift);
213 while (box[v][d] < -BOX_MARGIN_CORRECT*0.5*box[d][d]) {
214 if (fplog) {
215 fprintf(fplog,"Step %d: correcting invalid box:\n",step);
216 pr_rvecs(fplog,0,"old box",box,DIM);
218 rvec_inc(box[v],box[d]);
219 shift++;
220 if (fplog) {
221 pr_rvecs(fplog,0,"new box",box,DIM);
223 if (shift >= maxshift)
224 gmx_fatal(FARGS,
225 "Box was shifted at least %d times. Please see log-file.",
226 maxshift);
229 return shift;
232 gmx_bool correct_box(FILE *fplog,int step,tensor box,t_graph *graph)
234 int zy,zx,yx,i;
235 gmx_bool bCorrected;
237 /* check if the box still obeys the restrictions, if not, correct it */
238 zy = correct_box_elem(fplog,step,box,ZZ,YY);
239 zx = correct_box_elem(fplog,step,box,ZZ,XX);
240 yx = correct_box_elem(fplog,step,box,YY,XX);
242 bCorrected = (zy || zx || yx);
244 if (bCorrected && graph) {
245 /* correct the graph */
246 for(i=0; i<graph->nnodes; i++) {
247 graph->ishift[i][YY] -= graph->ishift[i][ZZ]*zy;
248 graph->ishift[i][XX] -= graph->ishift[i][ZZ]*zx;
249 graph->ishift[i][XX] -= graph->ishift[i][YY]*yx;
253 return bCorrected;
256 int ndof_com(t_inputrec *ir)
258 int n=0;
260 switch (ir->ePBC) {
261 case epbcXYZ:
262 case epbcNONE:
263 n = 3;
264 break;
265 case epbcXY:
266 n = (ir->nwall == 0 ? 3 : 2);
267 break;
268 case epbcSCREW:
269 n = 1;
270 break;
271 default:
272 gmx_incons("Unknown pbc in calc_nrdf");
275 return n;
278 static void low_set_pbc(t_pbc *pbc,int ePBC,ivec *dd_nc,matrix box)
280 int order[5]={0,-1,1,-2,2};
281 int ii,jj,kk,i,j,k,d,dd,jc,kc,npbcdim,shift;
282 ivec bPBC;
283 real d2old,d2new,d2new_c;
284 rvec trial,pos;
285 gmx_bool bXY,bUse;
286 const char *ptr;
288 pbc->ndim_ePBC = ePBC2npbcdim(ePBC);
290 copy_mat(box,pbc->box);
291 pbc->bLimitDistance = FALSE;
292 pbc->max_cutoff2 = 0;
293 pbc->dim = -1;
295 for(i=0; (i<DIM); i++) {
296 pbc->fbox_diag[i] = box[i][i];
297 pbc->hbox_diag[i] = pbc->fbox_diag[i]*0.5;
298 pbc->mhbox_diag[i] = -pbc->hbox_diag[i];
301 ptr = check_box(ePBC,box);
302 if (ePBC == epbcNONE) {
303 pbc->ePBCDX = epbcdxNOPBC;
304 } else if (ptr) {
305 fprintf(stderr, "Warning: %s\n",ptr);
306 pr_rvecs(stderr,0," Box",box,DIM);
307 fprintf(stderr, " Can not fix pbc.\n");
308 pbc->ePBCDX = epbcdxUNSUPPORTED;
309 pbc->bLimitDistance = TRUE;
310 pbc->limit_distance2 = 0;
311 } else {
312 if (ePBC == epbcSCREW && dd_nc) {
313 /* This combinated should never appear here */
314 gmx_incons("low_set_pbc called with screw pbc and dd_nc != NULL");
317 npbcdim = 0;
318 for(i=0; i<DIM; i++) {
319 if ((dd_nc && (*dd_nc)[i] > 1) || (ePBC == epbcXY && i == ZZ)) {
320 bPBC[i] = 0;
321 } else {
322 bPBC[i] = 1;
323 npbcdim++;
326 switch (npbcdim) {
327 case 1:
328 /* 1D pbc is not an mdp option and it is therefore only used
329 * with single shifts.
331 pbc->ePBCDX = epbcdx1D_RECT;
332 for(i=0; i<DIM; i++)
333 if (bPBC[i])
334 pbc->dim = i;
335 for(i=0; i<pbc->dim; i++)
336 if (pbc->box[pbc->dim][i] != 0)
337 pbc->ePBCDX = epbcdx1D_TRIC;
338 break;
339 case 2:
340 pbc->ePBCDX = epbcdx2D_RECT;
341 for(i=0; i<DIM; i++)
342 if (!bPBC[i])
343 pbc->dim = i;
344 for(i=0; i<DIM; i++)
345 if (bPBC[i])
346 for(j=0; j<i; j++)
347 if (pbc->box[i][j] != 0)
348 pbc->ePBCDX = epbcdx2D_TRIC;
349 break;
350 case 3:
351 if (ePBC != epbcSCREW) {
352 if (TRICLINIC(box)) {
353 pbc->ePBCDX = epbcdxTRICLINIC;
354 } else {
355 pbc->ePBCDX = epbcdxRECTANGULAR;
357 } else {
358 pbc->ePBCDX = (box[ZZ][YY]==0 ? epbcdxSCREW_RECT : epbcdxSCREW_TRIC);
359 if (pbc->ePBCDX == epbcdxSCREW_TRIC) {
360 fprintf(stderr,
361 "Screw pbc is not yet implemented for triclinic boxes.\n"
362 "Can not fix pbc.\n");
363 pbc->ePBCDX = epbcdxUNSUPPORTED;
366 break;
367 default:
368 gmx_fatal(FARGS,"Incorrect number of pbc dimensions with DD: %d",
369 npbcdim);
371 pbc->max_cutoff2 = max_cutoff2(ePBC,box);
373 if (pbc->ePBCDX == epbcdxTRICLINIC ||
374 pbc->ePBCDX == epbcdx2D_TRIC ||
375 pbc->ePBCDX == epbcdxSCREW_TRIC) {
376 if (debug) {
377 pr_rvecs(debug,0,"Box",box,DIM);
378 fprintf(debug,"max cutoff %.3f\n",sqrt(pbc->max_cutoff2));
380 pbc->ntric_vec = 0;
381 /* We will only use single shifts, but we will check a few
382 * more shifts to see if there is a limiting distance
383 * above which we can not be sure of the correct distance.
385 for(kk=0; kk<5; kk++) {
386 k = order[kk];
387 if (!bPBC[ZZ] && k != 0)
388 continue;
389 for(jj=0; jj<5; jj++) {
390 j = order[jj];
391 if (!bPBC[YY] && j != 0)
392 continue;
393 for(ii=0; ii<3; ii++) {
394 i = order[ii];
395 if (!bPBC[XX] && i != 0)
396 continue;
397 /* A shift is only useful when it is trilinic */
398 if (j != 0 || k != 0) {
399 d2old = 0;
400 d2new = 0;
401 for(d=0; d<DIM; d++) {
402 trial[d] = i*box[XX][d] + j*box[YY][d] + k*box[ZZ][d];
403 /* Choose the vector within the brick around 0,0,0 that
404 * will become the shortest due to shift try.
406 if (d == pbc->dim) {
407 trial[d] = 0;
408 pos[d] = 0;
409 } else {
410 if (trial[d] < 0)
411 pos[d] = min( pbc->hbox_diag[d],-trial[d]);
412 else
413 pos[d] = max(-pbc->hbox_diag[d],-trial[d]);
415 d2old += sqr(pos[d]);
416 d2new += sqr(pos[d] + trial[d]);
418 if (BOX_MARGIN*d2new < d2old) {
419 if (j < -1 || j > 1 || k < -1 || k > 1) {
420 /* Check if there is a single shift vector
421 * that decreases this distance even more.
423 jc = 0;
424 kc = 0;
425 if (j < -1 || j > 1)
426 jc = j/2;
427 if (k < -1 || k > 1)
428 kc = k/2;
429 d2new_c = 0;
430 for(d=0; d<DIM; d++)
431 d2new_c += sqr(pos[d] + trial[d]
432 - jc*box[YY][d] - kc*box[ZZ][d]);
433 if (d2new_c > BOX_MARGIN*d2new) {
434 /* Reject this shift vector, as there is no a priori limit
435 * to the number of shifts that decrease distances.
437 if (!pbc->bLimitDistance || d2new < pbc->limit_distance2)
438 pbc->limit_distance2 = d2new;
439 pbc->bLimitDistance = TRUE;
441 } else {
442 /* Check if shifts with one box vector less do better */
443 bUse = TRUE;
444 for(dd=0; dd<DIM; dd++) {
445 shift = (dd==0 ? i : (dd==1 ? j : k));
446 if (shift) {
447 d2new_c = 0;
448 for(d=0; d<DIM; d++)
449 d2new_c += sqr(pos[d] + trial[d] - shift*box[dd][d]);
450 if (d2new_c <= BOX_MARGIN*d2new)
451 bUse = FALSE;
454 if (bUse) {
455 /* Accept this shift vector. */
456 if (pbc->ntric_vec >= MAX_NTRICVEC) {
457 fprintf(stderr,"\nWARNING: Found more than %d triclinic correction vectors, ignoring some.\n"
458 " There is probably something wrong with your box.\n",MAX_NTRICVEC);
459 pr_rvecs(stderr,0," Box",box,DIM);
460 } else {
461 copy_rvec(trial,pbc->tric_vec[pbc->ntric_vec]);
462 pbc->tric_shift[pbc->ntric_vec][XX] = i;
463 pbc->tric_shift[pbc->ntric_vec][YY] = j;
464 pbc->tric_shift[pbc->ntric_vec][ZZ] = k;
465 pbc->ntric_vec++;
469 if (debug) {
470 fprintf(debug," tricvec %2d = %2d %2d %2d %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
471 pbc->ntric_vec,i,j,k,
472 sqrt(d2old),sqrt(d2new),
473 trial[XX],trial[YY],trial[ZZ],
474 pos[XX],pos[YY],pos[ZZ]);
485 void set_pbc(t_pbc *pbc,int ePBC,matrix box)
487 if (ePBC == -1)
488 ePBC = guess_ePBC(box);
490 low_set_pbc(pbc,ePBC,NULL,box);
493 t_pbc *set_pbc_dd(t_pbc *pbc,int ePBC,
494 gmx_domdec_t *dd,gmx_bool bSingleDir,matrix box)
496 ivec nc2;
497 int npbcdim,i;
499 if (dd == NULL) {
500 npbcdim = DIM;
501 } else {
502 if (ePBC == epbcSCREW && dd->nc[XX] > 1) {
503 /* The rotation has been taken care of during coordinate communication */
504 ePBC = epbcXYZ;
506 npbcdim = 0;
507 for(i=0; i<DIM; i++) {
508 if (dd->nc[i] <= (bSingleDir ? 1 : 2)) {
509 nc2[i] = 1;
510 if (!(ePBC == epbcXY && i == ZZ))
511 npbcdim++;
512 } else {
513 nc2[i] = dd->nc[i];
518 if (npbcdim > 0)
519 low_set_pbc(pbc,ePBC,npbcdim<DIM ? &nc2 : NULL,box);
521 return (npbcdim > 0 ? pbc : NULL);
524 void pbc_dx(const t_pbc *pbc,const rvec x1, const rvec x2, rvec dx)
526 int i,j;
527 rvec dx_start,trial;
528 real d2min,d2trial;
529 gmx_bool bRot;
531 rvec_sub(x1,x2,dx);
533 switch (pbc->ePBCDX) {
534 case epbcdxRECTANGULAR:
535 for(i=0; i<DIM; i++) {
536 while (dx[i] > pbc->hbox_diag[i]) {
537 dx[i] -= pbc->fbox_diag[i];
539 while (dx[i] <= pbc->mhbox_diag[i]) {
540 dx[i] += pbc->fbox_diag[i];
543 break;
544 case epbcdxTRICLINIC:
545 for(i=DIM-1; i>=0; i--) {
546 while (dx[i] > pbc->hbox_diag[i]) {
547 for (j=i; j>=0; j--)
548 dx[j] -= pbc->box[i][j];
550 while (dx[i] <= pbc->mhbox_diag[i]) {
551 for (j=i; j>=0; j--)
552 dx[j] += pbc->box[i][j];
555 /* dx is the distance in a rectangular box */
556 d2min = norm2(dx);
557 if (d2min > pbc->max_cutoff2) {
558 copy_rvec(dx,dx_start);
559 d2min = norm2(dx);
560 /* Now try all possible shifts, when the distance is within max_cutoff
561 * it must be the shortest possible distance.
563 i = 0;
564 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
565 rvec_add(dx_start,pbc->tric_vec[i],trial);
566 d2trial = norm2(trial);
567 if (d2trial < d2min) {
568 copy_rvec(trial,dx);
569 d2min = d2trial;
571 i++;
574 break;
575 case epbcdx2D_RECT:
576 for(i=0; i<DIM; i++) {
577 if (i != pbc->dim) {
578 while (dx[i] > pbc->hbox_diag[i]) {
579 dx[i] -= pbc->fbox_diag[i];
581 while (dx[i] <= pbc->mhbox_diag[i]) {
582 dx[i] += pbc->fbox_diag[i];
586 break;
587 case epbcdx2D_TRIC:
588 d2min = 0;
589 for(i=DIM-1; i>=0; i--) {
590 if (i != pbc->dim) {
591 while (dx[i] > pbc->hbox_diag[i]) {
592 for (j=i; j>=0; j--)
593 dx[j] -= pbc->box[i][j];
595 while (dx[i] <= pbc->mhbox_diag[i]) {
596 for (j=i; j>=0; j--)
597 dx[j] += pbc->box[i][j];
599 d2min += dx[i]*dx[i];
602 if (d2min > pbc->max_cutoff2) {
603 copy_rvec(dx,dx_start);
604 d2min = norm2(dx);
605 /* Now try all possible shifts, when the distance is within max_cutoff
606 * it must be the shortest possible distance.
608 i = 0;
609 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
610 rvec_add(dx_start,pbc->tric_vec[i],trial);
611 d2trial = 0;
612 for(j=0; j<DIM; j++) {
613 if (j != pbc->dim) {
614 d2trial += trial[j]*trial[j];
617 if (d2trial < d2min) {
618 copy_rvec(trial,dx);
619 d2min = d2trial;
621 i++;
624 break;
625 case epbcdxSCREW_RECT:
626 /* The shift definition requires x first */
627 bRot = FALSE;
628 while (dx[XX] > pbc->hbox_diag[XX]) {
629 dx[XX] -= pbc->fbox_diag[XX];
630 bRot = !bRot;
632 while (dx[XX] <= pbc->mhbox_diag[XX]) {
633 dx[XX] += pbc->fbox_diag[YY];
634 bRot = !bRot;
636 if (bRot) {
637 /* Rotate around the x-axis in the middle of the box */
638 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
639 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
641 /* Normal pbc for y and z */
642 for(i=YY; i<=ZZ; i++) {
643 while (dx[i] > pbc->hbox_diag[i]) {
644 dx[i] -= pbc->fbox_diag[i];
646 while (dx[i] <= pbc->mhbox_diag[i]) {
647 dx[i] += pbc->fbox_diag[i];
650 break;
651 case epbcdxNOPBC:
652 case epbcdxUNSUPPORTED:
653 break;
654 default:
655 gmx_fatal(FARGS,"Internal error in pbc_dx, set_pbc has not been called");
656 break;
660 int pbc_dx_aiuc(const t_pbc *pbc,const rvec x1, const rvec x2, rvec dx)
662 int i,j,is;
663 rvec dx_start,trial;
664 real d2min,d2trial;
665 ivec ishift,ishift_start;
667 rvec_sub(x1,x2,dx);
668 clear_ivec(ishift);
670 switch (pbc->ePBCDX) {
671 case epbcdxRECTANGULAR:
672 for(i=0; i<DIM; i++) {
673 if (dx[i] > pbc->hbox_diag[i]) {
674 dx[i] -= pbc->fbox_diag[i];
675 ishift[i]--;
676 } else if (dx[i] <= pbc->mhbox_diag[i]) {
677 dx[i] += pbc->fbox_diag[i];
678 ishift[i]++;
681 break;
682 case epbcdxTRICLINIC:
683 /* For triclinic boxes the performance difference between
684 * if/else and two while loops is negligible.
685 * However, the while version can cause extreme delays
686 * before a simulation crashes due to large forces which
687 * can cause unlimited displacements.
688 * Also allowing multiple shifts would index fshift beyond bounds.
690 for(i=DIM-1; i>=1; i--) {
691 if (dx[i] > pbc->hbox_diag[i]) {
692 for (j=i; j>=0; j--)
693 dx[j] -= pbc->box[i][j];
694 ishift[i]--;
695 } else if (dx[i] <= pbc->mhbox_diag[i]) {
696 for (j=i; j>=0; j--)
697 dx[j] += pbc->box[i][j];
698 ishift[i]++;
701 /* Allow 2 shifts in x */
702 if (dx[XX] > pbc->hbox_diag[XX]) {
703 dx[XX] -= pbc->fbox_diag[XX];
704 ishift[XX]--;
705 if (dx[XX] > pbc->hbox_diag[XX]) {
706 dx[XX] -= pbc->fbox_diag[XX];
707 ishift[XX]--;
709 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
710 dx[XX] += pbc->fbox_diag[XX];
711 ishift[XX]++;
712 if (dx[XX] <= pbc->mhbox_diag[XX]) {
713 dx[XX] += pbc->fbox_diag[XX];
714 ishift[XX]++;
717 /* dx is the distance in a rectangular box */
718 d2min = norm2(dx);
719 if (d2min > pbc->max_cutoff2) {
720 copy_rvec(dx,dx_start);
721 copy_ivec(ishift,ishift_start);
722 d2min = norm2(dx);
723 /* Now try all possible shifts, when the distance is within max_cutoff
724 * it must be the shortest possible distance.
726 i = 0;
727 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
728 rvec_add(dx_start,pbc->tric_vec[i],trial);
729 d2trial = norm2(trial);
730 if (d2trial < d2min) {
731 copy_rvec(trial,dx);
732 ivec_add(ishift_start,pbc->tric_shift[i],ishift);
733 d2min = d2trial;
735 i++;
738 break;
739 case epbcdx2D_RECT:
740 for(i=0; i<DIM; i++) {
741 if (i != pbc->dim) {
742 if (dx[i] > pbc->hbox_diag[i]) {
743 dx[i] -= pbc->fbox_diag[i];
744 ishift[i]--;
745 } else if (dx[i] <= pbc->mhbox_diag[i]) {
746 dx[i] += pbc->fbox_diag[i];
747 ishift[i]++;
751 break;
752 case epbcdx2D_TRIC:
753 d2min = 0;
754 for(i=DIM-1; i>=1; i--) {
755 if (i != pbc->dim) {
756 if (dx[i] > pbc->hbox_diag[i]) {
757 for (j=i; j>=0; j--)
758 dx[j] -= pbc->box[i][j];
759 ishift[i]--;
760 } else if (dx[i] <= pbc->mhbox_diag[i]) {
761 for (j=i; j>=0; j--)
762 dx[j] += pbc->box[i][j];
763 ishift[i]++;
765 d2min += dx[i]*dx[i];
768 if (pbc->dim != XX) {
769 /* Allow 2 shifts in x */
770 if (dx[XX] > pbc->hbox_diag[XX]) {
771 dx[XX] -= pbc->fbox_diag[XX];
772 ishift[XX]--;
773 if (dx[XX] > pbc->hbox_diag[XX]) {
774 dx[XX] -= pbc->fbox_diag[XX];
775 ishift[XX]--;
777 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
778 dx[XX] += pbc->fbox_diag[XX];
779 ishift[XX]++;
780 if (dx[XX] <= pbc->mhbox_diag[XX]) {
781 dx[XX] += pbc->fbox_diag[XX];
782 ishift[XX]++;
785 d2min += dx[XX]*dx[XX];
787 if (d2min > pbc->max_cutoff2) {
788 copy_rvec(dx,dx_start);
789 copy_ivec(ishift,ishift_start);
790 /* Now try all possible shifts, when the distance is within max_cutoff
791 * it must be the shortest possible distance.
793 i = 0;
794 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
795 rvec_add(dx_start,pbc->tric_vec[i],trial);
796 d2trial = 0;
797 for(j=0; j<DIM; j++) {
798 if (j != pbc->dim) {
799 d2trial += trial[j]*trial[j];
802 if (d2trial < d2min) {
803 copy_rvec(trial,dx);
804 ivec_add(ishift_start,pbc->tric_shift[i],ishift);
805 d2min = d2trial;
807 i++;
810 break;
811 case epbcdx1D_RECT:
812 i = pbc->dim;
813 if (dx[i] > pbc->hbox_diag[i]) {
814 dx[i] -= pbc->fbox_diag[i];
815 ishift[i]--;
816 } else if (dx[i] <= pbc->mhbox_diag[i]) {
817 dx[i] += pbc->fbox_diag[i];
818 ishift[i]++;
820 break;
821 case epbcdx1D_TRIC:
822 i = pbc->dim;
823 if (dx[i] > pbc->hbox_diag[i]) {
824 rvec_dec(dx,pbc->box[i]);
825 ishift[i]--;
826 } else if (dx[i] <= pbc->mhbox_diag[i]) {
827 rvec_inc(dx,pbc->box[i]);
828 ishift[i]++;
830 break;
831 case epbcdxSCREW_RECT:
832 /* The shift definition requires x first */
833 if (dx[XX] > pbc->hbox_diag[XX]) {
834 dx[XX] -= pbc->fbox_diag[XX];
835 ishift[XX]--;
836 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
837 dx[XX] += pbc->fbox_diag[XX];
838 ishift[XX]++;
840 if (ishift[XX] == 1 || ishift[XX] == -1) {
841 /* Rotate around the x-axis in the middle of the box */
842 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
843 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
845 /* Normal pbc for y and z */
846 for(i=YY; i<=ZZ; i++) {
847 if (dx[i] > pbc->hbox_diag[i]) {
848 dx[i] -= pbc->fbox_diag[i];
849 ishift[i]--;
850 } else if (dx[i] <= pbc->mhbox_diag[i]) {
851 dx[i] += pbc->fbox_diag[i];
852 ishift[i]++;
855 break;
856 case epbcdxNOPBC:
857 case epbcdxUNSUPPORTED:
858 break;
859 default:
860 gmx_fatal(FARGS,"Internal error in pbc_dx_aiuc, set_pbc_dd or set_pbc has not been called");
861 break;
864 is = IVEC2IS(ishift);
865 if (debug)
867 range_check_mesg(is,0,SHIFTS,"PBC shift vector index range check.");
870 return is;
873 void pbc_dx_d(const t_pbc *pbc,const dvec x1, const dvec x2, dvec dx)
875 int i,j;
876 dvec dx_start,trial;
877 double d2min,d2trial;
878 gmx_bool bRot;
880 dvec_sub(x1,x2,dx);
882 switch (pbc->ePBCDX) {
883 case epbcdxRECTANGULAR:
884 case epbcdx2D_RECT:
885 for(i=0; i<DIM; i++) {
886 if (i != pbc->dim) {
887 while (dx[i] > pbc->hbox_diag[i]) {
888 dx[i] -= pbc->fbox_diag[i];
890 while (dx[i] <= pbc->mhbox_diag[i]) {
891 dx[i] += pbc->fbox_diag[i];
895 break;
896 case epbcdxTRICLINIC:
897 case epbcdx2D_TRIC:
898 d2min = 0;
899 for(i=DIM-1; i>=0; i--) {
900 if (i != pbc->dim) {
901 while (dx[i] > pbc->hbox_diag[i]) {
902 for (j=i; j>=0; j--)
903 dx[j] -= pbc->box[i][j];
905 while (dx[i] <= pbc->mhbox_diag[i]) {
906 for (j=i; j>=0; j--)
907 dx[j] += pbc->box[i][j];
909 d2min += dx[i]*dx[i];
912 if (d2min > pbc->max_cutoff2) {
913 copy_dvec(dx,dx_start);
914 /* Now try all possible shifts, when the distance is within max_cutoff
915 * it must be the shortest possible distance.
917 i = 0;
918 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
919 for(j=0; j<DIM; j++) {
920 trial[j] = dx_start[j] + pbc->tric_vec[i][j];
922 d2trial = 0;
923 for(j=0; j<DIM; j++) {
924 if (j != pbc->dim) {
925 d2trial += trial[j]*trial[j];
928 if (d2trial < d2min) {
929 copy_dvec(trial,dx);
930 d2min = d2trial;
932 i++;
935 break;
936 case epbcdxSCREW_RECT:
937 /* The shift definition requires x first */
938 bRot = FALSE;
939 while (dx[XX] > pbc->hbox_diag[XX]) {
940 dx[XX] -= pbc->fbox_diag[XX];
941 bRot = !bRot;
943 while (dx[XX] <= pbc->mhbox_diag[XX]) {
944 dx[XX] += pbc->fbox_diag[YY];
945 bRot = !bRot;
947 if (bRot) {
948 /* Rotate around the x-axis in the middle of the box */
949 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
950 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
952 /* Normal pbc for y and z */
953 for(i=YY; i<=ZZ; i++) {
954 while (dx[i] > pbc->hbox_diag[i]) {
955 dx[i] -= pbc->fbox_diag[i];
957 while (dx[i] <= pbc->mhbox_diag[i]) {
958 dx[i] += pbc->fbox_diag[i];
961 break;
962 case epbcdxNOPBC:
963 case epbcdxUNSUPPORTED:
964 break;
965 default:
966 gmx_fatal(FARGS,"Internal error in pbc_dx, set_pbc has not been called");
967 break;
971 gmx_bool image_rect(ivec xi,ivec xj,ivec box_size,real rlong2,int *shift,real *r2)
973 int m,t;
974 int dx,b,b_2;
975 real dxr,rij2;
977 rij2=0.0;
978 t=0;
979 for(m=0; (m<DIM); m++) {
980 dx=xi[m]-xj[m];
981 t*=DIM;
982 b=box_size[m];
983 b_2=b/2;
984 if (dx < -b_2) {
985 t+=2;
986 dx+=b;
988 else if (dx > b_2)
989 dx-=b;
990 else
991 t+=1;
992 dxr=dx;
993 rij2+=dxr*dxr;
994 if (rij2 >= rlong2)
995 return FALSE;
998 *shift = t;
999 *r2 = rij2;
1000 return TRUE;
1003 gmx_bool image_cylindric(ivec xi,ivec xj,ivec box_size,real rlong2,
1004 int *shift,real *r2)
1006 int m,t;
1007 int dx,b,b_2;
1008 real dxr,rij2;
1010 rij2=0.0;
1011 t=0;
1012 for(m=0; (m<DIM); m++) {
1013 dx=xi[m]-xj[m];
1014 t*=DIM;
1015 b=box_size[m];
1016 b_2=b/2;
1017 if (dx < -b_2) {
1018 t+=2;
1019 dx+=b;
1021 else if (dx > b_2)
1022 dx-=b;
1023 else
1024 t+=1;
1026 dxr=dx;
1027 rij2+=dxr*dxr;
1028 if (m < ZZ) {
1029 if (rij2 >= rlong2)
1030 return FALSE;
1034 *shift = t;
1035 *r2 = rij2;
1036 return TRUE;
1039 void calc_shifts(matrix box,rvec shift_vec[])
1041 int k,l,m,d,n,test;
1043 n=0;
1044 for(m = -D_BOX_Z; m <= D_BOX_Z; m++)
1045 for(l = -D_BOX_Y; l <= D_BOX_Y; l++)
1046 for(k = -D_BOX_X; k <= D_BOX_X; k++,n++) {
1047 test = XYZ2IS(k,l,m);
1048 if (n != test)
1049 gmx_incons("inconsistent shift numbering");
1050 for(d = 0; d < DIM; d++)
1051 shift_vec[n][d] = k*box[XX][d] + l*box[YY][d] + m*box[ZZ][d];
1055 void calc_box_center(int ecenter,matrix box,rvec box_center)
1057 int d,m;
1059 clear_rvec(box_center);
1060 switch (ecenter) {
1061 case ecenterTRIC:
1062 for(m=0; (m<DIM); m++)
1063 for(d=0; d<DIM; d++)
1064 box_center[d] += 0.5*box[m][d];
1065 break;
1066 case ecenterRECT:
1067 for(d=0; d<DIM; d++)
1068 box_center[d] = 0.5*box[d][d];
1069 break;
1070 case ecenterZERO:
1071 break;
1072 default:
1073 gmx_fatal(FARGS,"Unsupported value %d for ecenter",ecenter);
1077 void calc_triclinic_images(matrix box,rvec img[])
1079 int i;
1081 /* Calculate 3 adjacent images in the xy-plane */
1082 copy_rvec(box[0],img[0]);
1083 copy_rvec(box[1],img[1]);
1084 if (img[1][XX] < 0)
1085 svmul(-1,img[1],img[1]);
1086 rvec_sub(img[1],img[0],img[2]);
1088 /* Get the next 3 in the xy-plane as mirror images */
1089 for(i=0; i<3; i++)
1090 svmul(-1,img[i],img[3+i]);
1092 /* Calculate the first 4 out of xy-plane images */
1093 copy_rvec(box[2],img[6]);
1094 if (img[6][XX] < 0)
1095 svmul(-1,img[6],img[6]);
1096 for(i=0; i<3; i++)
1097 rvec_add(img[6],img[i+1],img[7+i]);
1099 /* Mirror the last 4 from the previous in opposite rotation */
1100 for(i=0; i<4; i++)
1101 svmul(-1,img[6 + (2+i) % 4],img[10+i]);
1104 void calc_compact_unitcell_vertices(int ecenter,matrix box,rvec vert[])
1106 rvec img[NTRICIMG],box_center;
1107 int n,i,j,tmp[4],d;
1109 calc_triclinic_images(box,img);
1111 n=0;
1112 for(i=2; i<=5; i+=3) {
1113 tmp[0] = i-1;
1114 if (i==2)
1115 tmp[1] = 8;
1116 else
1117 tmp[1] = 6;
1118 tmp[2] = (i+1) % 6;
1119 tmp[3] = tmp[1]+4;
1120 for(j=0; j<4; j++) {
1121 for(d=0; d<DIM; d++)
1122 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1123 n++;
1126 for(i=7; i<=13; i+=6) {
1127 tmp[0] = (i-7)/2;
1128 tmp[1] = tmp[0]+1;
1129 if (i==7)
1130 tmp[2] = 8;
1131 else
1132 tmp[2] = 10;
1133 tmp[3] = i-1;
1134 for(j=0; j<4; j++) {
1135 for(d=0; d<DIM; d++)
1136 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1137 n++;
1140 for(i=9; i<=11; i+=2) {
1141 if (i==9)
1142 tmp[0] = 3;
1143 else
1144 tmp[0] = 0;
1145 tmp[1] = tmp[0]+1;
1146 if (i==9)
1147 tmp[2] = 6;
1148 else
1149 tmp[2] = 12;
1150 tmp[3] = i-1;
1151 for(j=0; j<4; j++) {
1152 for(d=0; d<DIM; d++)
1153 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1154 n++;
1158 calc_box_center(ecenter,box,box_center);
1159 for(i=0; i<NCUCVERT; i++)
1160 for(d=0; d<DIM; d++)
1161 vert[i][d] = vert[i][d]*0.25+box_center[d];
1164 int *compact_unitcell_edges()
1166 /* this is an index in vert[] (see calc_box_vertices) */
1167 /*static int edge[NCUCEDGE*2];*/
1168 int *edge;
1169 static const int hexcon[24] = { 0,9, 1,19, 2,15, 3,21,
1170 4,17, 5,11, 6,23, 7,13,
1171 8,20, 10,18, 12,16, 14,22 };
1172 int e,i,j;
1173 gmx_bool bFirst = TRUE;
1175 snew(edge,NCUCEDGE*2);
1177 if (bFirst) {
1178 e = 0;
1179 for(i=0; i<6; i++)
1180 for(j=0; j<4; j++) {
1181 edge[e++] = 4*i + j;
1182 edge[e++] = 4*i + (j+1) % 4;
1184 for(i=0; i<12*2; i++)
1185 edge[e++] = hexcon[i];
1187 bFirst = FALSE;
1190 return edge;
1193 void put_atom_in_box(matrix box,rvec x)
1195 int i,m,d;
1197 for(m=DIM-1; m>=0; m--) {
1198 while (x[m] < 0)
1199 for(d=0; d<=m; d++)
1200 x[d] += box[m][d];
1201 while (x[m] >= box[m][m])
1202 for(d=0; d<=m; d++)
1203 x[d] -= box[m][d];
1207 void put_atoms_in_box(matrix box,int natoms,rvec x[])
1209 int i,m,d;
1211 for(i=0; (i<natoms); i++)
1212 put_atom_in_box(box,x[i]);
1215 void put_atoms_in_triclinic_unitcell(int ecenter,matrix box,
1216 int natoms,rvec x[])
1218 rvec box_center,shift_center;
1219 real shm01,shm02,shm12,shift;
1220 int i,m,d;
1222 calc_box_center(ecenter,box,box_center);
1224 /* The product of matrix shm with a coordinate gives the shift vector
1225 which is required determine the periodic cell position */
1226 shm01 = box[1][0]/box[1][1];
1227 shm02 = (box[1][1]*box[2][0] - box[2][1]*box[1][0])/(box[1][1]*box[2][2]);
1228 shm12 = box[2][1]/box[2][2];
1230 clear_rvec(shift_center);
1231 for(d=0; d<DIM; d++)
1232 rvec_inc(shift_center,box[d]);
1233 svmul(0.5,shift_center,shift_center);
1234 rvec_sub(box_center,shift_center,shift_center);
1236 shift_center[0] = shm01*shift_center[1] + shm02*shift_center[2];
1237 shift_center[1] = shm12*shift_center[2];
1238 shift_center[2] = 0;
1240 for(i=0; (i<natoms); i++)
1241 for(m=DIM-1; m>=0; m--) {
1242 shift = shift_center[m];
1243 if (m == 0) {
1244 shift += shm01*x[i][1] + shm02*x[i][2];
1245 } else if (m == 1) {
1246 shift += shm12*x[i][2];
1248 while (x[i][m]-shift < 0)
1249 for(d=0; d<=m; d++)
1250 x[i][d] += box[m][d];
1251 while (x[i][m]-shift >= box[m][m])
1252 for(d=0; d<=m; d++)
1253 x[i][d] -= box[m][d];
1257 const char *
1258 put_atoms_in_compact_unitcell(int ePBC,int ecenter,matrix box,
1259 int natoms,rvec x[])
1261 t_pbc pbc;
1262 rvec box_center,dx;
1263 int i;
1265 set_pbc(&pbc,ePBC,box);
1266 calc_box_center(ecenter,box,box_center);
1267 for(i=0; i<natoms; i++) {
1268 pbc_dx(&pbc,x[i],box_center,dx);
1269 rvec_add(box_center,dx,x[i]);
1272 return pbc.bLimitDistance ?
1273 "WARNING: Could not put all atoms in the compact unitcell\n"
1274 : NULL;