split off warninp.c with input reading warning routines from gmx_fatal.c
[gromacs/rigid-bodies.git] / src / gmxlib / pbc.c
blob4f1f3cd263d21731fa1cc45ef5d8ac4047a57996
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 static bool bWarnedGuess=FALSE;
164 int guess_ePBC(matrix box)
166 int ePBC;
168 if (box[XX][XX]>0 && box[YY][YY]>0 && box[ZZ][ZZ]>0) {
169 ePBC = epbcXYZ;
170 } else if (box[XX][XX]>0 && box[YY][YY]>0 && box[ZZ][ZZ]==0) {
171 ePBC = epbcXY;
172 } else if (box[XX][XX]==0 && box[YY][YY]==0 && box[ZZ][ZZ]==0) {
173 ePBC = epbcNONE;
174 } else {
175 if (!bWarnedGuess) {
176 fprintf(stderr,"WARNING: Unsupported box diagonal %f %f %f, "
177 "will not use periodic boundary conditions\n\n",
178 box[XX][XX],box[YY][YY],box[ZZ][ZZ]);
179 bWarnedGuess = TRUE;
181 ePBC = epbcNONE;
184 if (debug)
185 fprintf(debug,"Guessed pbc = %s from the box matrix\n",epbc_names[ePBC]);
187 return ePBC;
190 static int correct_box_elem(FILE *fplog,int step,tensor box,int v,int d)
192 int shift,maxshift=10;
194 shift = 0;
196 /* correct elem d of vector v with vector d */
197 while (box[v][d] > BOX_MARGIN_CORRECT*0.5*box[d][d]) {
198 if (fplog) {
199 fprintf(fplog,"Step %d: correcting invalid box:\n",step);
200 pr_rvecs(fplog,0,"old box",box,DIM);
202 rvec_dec(box[v],box[d]);
203 shift--;
204 if (fplog) {
205 pr_rvecs(fplog,0,"new box",box,DIM);
207 if (shift <= -maxshift)
208 gmx_fatal(FARGS,
209 "Box was shifted at least %d times. Please see log-file.",
210 maxshift);
212 while (box[v][d] < -BOX_MARGIN_CORRECT*0.5*box[d][d]) {
213 if (fplog) {
214 fprintf(fplog,"Step %d: correcting invalid box:\n",step);
215 pr_rvecs(fplog,0,"old box",box,DIM);
217 rvec_inc(box[v],box[d]);
218 shift++;
219 if (fplog) {
220 pr_rvecs(fplog,0,"new box",box,DIM);
222 if (shift >= maxshift)
223 gmx_fatal(FARGS,
224 "Box was shifted at least %d times. Please see log-file.",
225 maxshift);
228 return shift;
231 bool correct_box(FILE *fplog,int step,tensor box,t_graph *graph)
233 int zy,zx,yx,i;
234 bool bCorrected;
236 /* check if the box still obeys the restrictions, if not, correct it */
237 zy = correct_box_elem(fplog,step,box,ZZ,YY);
238 zx = correct_box_elem(fplog,step,box,ZZ,XX);
239 yx = correct_box_elem(fplog,step,box,YY,XX);
241 bCorrected = (zy || zx || yx);
243 if (bCorrected && graph) {
244 /* correct the graph */
245 for(i=0; i<graph->nnodes; i++) {
246 graph->ishift[i][YY] -= graph->ishift[i][ZZ]*zy;
247 graph->ishift[i][XX] -= graph->ishift[i][ZZ]*zx;
248 graph->ishift[i][XX] -= graph->ishift[i][YY]*yx;
252 return bCorrected;
255 int ndof_com(t_inputrec *ir)
257 int n=0;
259 switch (ir->ePBC) {
260 case epbcXYZ:
261 case epbcNONE:
262 n = 3;
263 break;
264 case epbcXY:
265 n = (ir->nwall == 0 ? 3 : 2);
266 break;
267 case epbcSCREW:
268 n = 1;
269 break;
270 default:
271 gmx_incons("Unknown pbc in calc_nrdf");
274 return n;
277 static void low_set_pbc(t_pbc *pbc,int ePBC,ivec *dd_nc,matrix box)
279 int order[5]={0,-1,1,-2,2};
280 int ii,jj,kk,i,j,k,d,dd,jc,kc,npbcdim,shift;
281 ivec bPBC;
282 real d2old,d2new,d2new_c;
283 rvec trial,pos;
284 bool bXY,bUse;
285 const char *ptr;
287 pbc->ndim_ePBC = ePBC2npbcdim(ePBC);
289 copy_mat(box,pbc->box);
290 pbc->bLimitDistance = FALSE;
291 pbc->max_cutoff2 = 0;
292 pbc->dim = -1;
294 for(i=0; (i<DIM); i++) {
295 pbc->fbox_diag[i] = box[i][i];
296 pbc->hbox_diag[i] = pbc->fbox_diag[i]*0.5;
297 pbc->mhbox_diag[i] = -pbc->hbox_diag[i];
300 ptr = check_box(ePBC,box);
301 if (ePBC == epbcNONE) {
302 pbc->ePBCDX = epbcdxNOPBC;
303 } else if (ptr) {
304 fprintf(stderr, "Warning: %s\n",ptr);
305 pr_rvecs(stderr,0," Box",box,DIM);
306 fprintf(stderr, " Can not fix pbc.\n");
307 pbc->ePBCDX = epbcdxUNSUPPORTED;
308 pbc->bLimitDistance = TRUE;
309 pbc->limit_distance2 = 0;
310 } else {
311 if (ePBC == epbcSCREW && dd_nc) {
312 /* This combinated should never appear here */
313 gmx_incons("low_set_pbc called with screw pbc and dd_nc != NULL");
316 npbcdim = 0;
317 for(i=0; i<DIM; i++) {
318 if ((dd_nc && (*dd_nc)[i] > 1) || (ePBC == epbcXY && i == ZZ)) {
319 bPBC[i] = 0;
320 } else {
321 bPBC[i] = 1;
322 npbcdim++;
325 switch (npbcdim) {
326 case 1:
327 /* 1D pbc is not an mdp option and it is therefore only used
328 * with single shifts.
330 pbc->ePBCDX = epbcdx1D_RECT;
331 for(i=0; i<DIM; i++)
332 if (bPBC[i])
333 pbc->dim = i;
334 for(i=0; i<pbc->dim; i++)
335 if (pbc->box[pbc->dim][i] != 0)
336 pbc->ePBCDX = epbcdx1D_TRIC;
337 break;
338 case 2:
339 pbc->ePBCDX = epbcdx2D_RECT;
340 for(i=0; i<DIM; i++)
341 if (!bPBC[i])
342 pbc->dim = i;
343 for(i=0; i<DIM; i++)
344 if (bPBC[i])
345 for(j=0; j<i; j++)
346 if (pbc->box[i][j] != 0)
347 pbc->ePBCDX = epbcdx2D_TRIC;
348 break;
349 case 3:
350 if (ePBC != epbcSCREW) {
351 if (TRICLINIC(box)) {
352 pbc->ePBCDX = epbcdxTRICLINIC;
353 } else {
354 pbc->ePBCDX = epbcdxRECTANGULAR;
356 } else {
357 pbc->ePBCDX = (box[ZZ][YY]==0 ? epbcdxSCREW_RECT : epbcdxSCREW_TRIC);
358 if (pbc->ePBCDX == epbcdxSCREW_TRIC) {
359 fprintf(stderr,
360 "Screw pbc is not yet implemented for triclinic boxes.\n"
361 "Can not fix pbc.\n");
362 pbc->ePBCDX = epbcdxUNSUPPORTED;
365 break;
366 default:
367 gmx_fatal(FARGS,"Incorrect number of pbc dimensions with DD: %d",
368 npbcdim);
370 pbc->max_cutoff2 = max_cutoff2(ePBC,box);
372 if (pbc->ePBCDX == epbcdxTRICLINIC ||
373 pbc->ePBCDX == epbcdx2D_TRIC ||
374 pbc->ePBCDX == epbcdxSCREW_TRIC) {
375 if (debug) {
376 pr_rvecs(debug,0,"Box",box,DIM);
377 fprintf(debug,"max cutoff %.3f\n",sqrt(pbc->max_cutoff2));
379 pbc->ntric_vec = 0;
380 /* We will only use single shifts, but we will check a few
381 * more shifts to see if there is a limiting distance
382 * above which we can not be sure of the correct distance.
384 for(kk=0; kk<5; kk++) {
385 k = order[kk];
386 if (!bPBC[ZZ] && k != 0)
387 continue;
388 for(jj=0; jj<5; jj++) {
389 j = order[jj];
390 if (!bPBC[YY] && j != 0)
391 continue;
392 for(ii=0; ii<3; ii++) {
393 i = order[ii];
394 if (!bPBC[XX] && i != 0)
395 continue;
396 /* A shift is only useful when it is trilinic */
397 if (j != 0 || k != 0) {
398 d2old = 0;
399 d2new = 0;
400 for(d=0; d<DIM; d++) {
401 trial[d] = i*box[XX][d] + j*box[YY][d] + k*box[ZZ][d];
402 /* Choose the vector within the brick around 0,0,0 that
403 * will become the shortest due to shift try.
405 if (d == pbc->dim) {
406 trial[d] = 0;
407 pos[d] = 0;
408 } else {
409 if (trial[d] < 0)
410 pos[d] = min( pbc->hbox_diag[d],-trial[d]);
411 else
412 pos[d] = max(-pbc->hbox_diag[d],-trial[d]);
414 d2old += sqr(pos[d]);
415 d2new += sqr(pos[d] + trial[d]);
417 if (BOX_MARGIN*d2new < d2old) {
418 if (j < -1 || j > 1 || k < -1 || k > 1) {
419 /* Check if there is a single shift vector
420 * that decreases this distance even more.
422 jc = 0;
423 kc = 0;
424 if (j < -1 || j > 1)
425 jc = j/2;
426 if (k < -1 || k > 1)
427 kc = k/2;
428 d2new_c = 0;
429 for(d=0; d<DIM; d++)
430 d2new_c += sqr(pos[d] + trial[d]
431 - jc*box[YY][d] - kc*box[ZZ][d]);
432 if (d2new_c > BOX_MARGIN*d2new) {
433 /* Reject this shift vector, as there is no a priori limit
434 * to the number of shifts that decrease distances.
436 if (!pbc->bLimitDistance || d2new < pbc->limit_distance2)
437 pbc->limit_distance2 = d2new;
438 pbc->bLimitDistance = TRUE;
440 } else {
441 /* Check if shifts with one box vector less do better */
442 bUse = TRUE;
443 for(dd=0; dd<DIM; dd++) {
444 shift = (dd==0 ? i : (dd==1 ? j : k));
445 if (shift) {
446 d2new_c = 0;
447 for(d=0; d<DIM; d++)
448 d2new_c += sqr(pos[d] + trial[d] - shift*box[dd][d]);
449 if (d2new_c <= BOX_MARGIN*d2new)
450 bUse = FALSE;
453 if (bUse) {
454 /* Accept this shift vector. */
455 if (pbc->ntric_vec >= MAX_NTRICVEC) {
456 fprintf(stderr,"\nWARNING: Found more than %d triclinic correction vectors, ignoring some.\n"
457 " There is probably something wrong with your box.\n",MAX_NTRICVEC);
458 pr_rvecs(stderr,0," Box",box,DIM);
459 } else {
460 copy_rvec(trial,pbc->tric_vec[pbc->ntric_vec]);
461 pbc->tric_shift[pbc->ntric_vec][XX] = i;
462 pbc->tric_shift[pbc->ntric_vec][YY] = j;
463 pbc->tric_shift[pbc->ntric_vec][ZZ] = k;
464 pbc->ntric_vec++;
468 if (debug) {
469 fprintf(debug," tricvec %2d = %2d %2d %2d %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
470 pbc->ntric_vec,i,j,k,
471 sqrt(d2old),sqrt(d2new),
472 trial[XX],trial[YY],trial[ZZ],
473 pos[XX],pos[YY],pos[ZZ]);
484 void set_pbc(t_pbc *pbc,int ePBC,matrix box)
486 if (ePBC == -1)
487 ePBC = guess_ePBC(box);
489 low_set_pbc(pbc,ePBC,NULL,box);
492 t_pbc *set_pbc_dd(t_pbc *pbc,int ePBC,
493 gmx_domdec_t *dd,bool bSingleDir,matrix box)
495 ivec nc2;
496 int npbcdim,i;
498 if (dd == NULL) {
499 npbcdim = DIM;
500 } else {
501 if (ePBC == epbcSCREW && dd->nc[XX] > 1) {
502 /* The rotation has been taken care of during coordinate communication */
503 ePBC = epbcXYZ;
505 npbcdim = 0;
506 for(i=0; i<DIM; i++) {
507 if (dd->nc[i] <= (bSingleDir ? 1 : 2)) {
508 nc2[i] = 1;
509 if (!(ePBC == epbcXY && i == ZZ))
510 npbcdim++;
511 } else {
512 nc2[i] = dd->nc[i];
517 if (npbcdim > 0)
518 low_set_pbc(pbc,ePBC,npbcdim<DIM ? &nc2 : NULL,box);
520 return (npbcdim > 0 ? pbc : NULL);
523 void pbc_dx(const t_pbc *pbc,const rvec x1, const rvec x2, rvec dx)
525 int i,j;
526 rvec dx_start,trial;
527 real d2min,d2trial;
528 bool bRot;
530 rvec_sub(x1,x2,dx);
532 switch (pbc->ePBCDX) {
533 case epbcdxRECTANGULAR:
534 for(i=0; i<DIM; i++) {
535 while (dx[i] > pbc->hbox_diag[i]) {
536 dx[i] -= pbc->fbox_diag[i];
538 while (dx[i] <= pbc->mhbox_diag[i]) {
539 dx[i] += pbc->fbox_diag[i];
542 break;
543 case epbcdxTRICLINIC:
544 for(i=DIM-1; i>=0; i--) {
545 while (dx[i] > pbc->hbox_diag[i]) {
546 for (j=i; j>=0; j--)
547 dx[j] -= pbc->box[i][j];
549 while (dx[i] <= pbc->mhbox_diag[i]) {
550 for (j=i; j>=0; j--)
551 dx[j] += pbc->box[i][j];
554 /* dx is the distance in a rectangular box */
555 d2min = norm2(dx);
556 if (d2min > pbc->max_cutoff2) {
557 copy_rvec(dx,dx_start);
558 d2min = norm2(dx);
559 /* Now try all possible shifts, when the distance is within max_cutoff
560 * it must be the shortest possible distance.
562 i = 0;
563 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
564 rvec_add(dx_start,pbc->tric_vec[i],trial);
565 d2trial = norm2(trial);
566 if (d2trial < d2min) {
567 copy_rvec(trial,dx);
568 d2min = d2trial;
570 i++;
573 break;
574 case epbcdx2D_RECT:
575 for(i=0; i<DIM; i++) {
576 if (i != pbc->dim) {
577 while (dx[i] > pbc->hbox_diag[i]) {
578 dx[i] -= pbc->fbox_diag[i];
580 while (dx[i] <= pbc->mhbox_diag[i]) {
581 dx[i] += pbc->fbox_diag[i];
585 break;
586 case epbcdx2D_TRIC:
587 d2min = 0;
588 for(i=DIM-1; i>=0; i--) {
589 if (i != pbc->dim) {
590 while (dx[i] > pbc->hbox_diag[i]) {
591 for (j=i; j>=0; j--)
592 dx[j] -= pbc->box[i][j];
594 while (dx[i] <= pbc->mhbox_diag[i]) {
595 for (j=i; j>=0; j--)
596 dx[j] += pbc->box[i][j];
598 d2min += dx[i]*dx[i];
601 if (d2min > pbc->max_cutoff2) {
602 copy_rvec(dx,dx_start);
603 d2min = norm2(dx);
604 /* Now try all possible shifts, when the distance is within max_cutoff
605 * it must be the shortest possible distance.
607 i = 0;
608 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
609 rvec_add(dx_start,pbc->tric_vec[i],trial);
610 d2trial = 0;
611 for(j=0; j<DIM; j++) {
612 if (j != pbc->dim) {
613 d2trial += trial[j]*trial[j];
616 if (d2trial < d2min) {
617 copy_rvec(trial,dx);
618 d2min = d2trial;
620 i++;
623 break;
624 case epbcdxSCREW_RECT:
625 /* The shift definition requires x first */
626 bRot = FALSE;
627 while (dx[XX] > pbc->hbox_diag[XX]) {
628 dx[XX] -= pbc->fbox_diag[XX];
629 bRot = !bRot;
631 while (dx[XX] <= pbc->mhbox_diag[XX]) {
632 dx[XX] += pbc->fbox_diag[YY];
633 bRot = !bRot;
635 if (bRot) {
636 /* Rotate around the x-axis in the middle of the box */
637 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
638 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
640 /* Normal pbc for y and z */
641 for(i=YY; i<=ZZ; i++) {
642 while (dx[i] > pbc->hbox_diag[i]) {
643 dx[i] -= pbc->fbox_diag[i];
645 while (dx[i] <= pbc->mhbox_diag[i]) {
646 dx[i] += pbc->fbox_diag[i];
649 break;
650 case epbcdxNOPBC:
651 case epbcdxUNSUPPORTED:
652 break;
653 default:
654 gmx_fatal(FARGS,"Internal error in pbc_dx, set_pbc has not been called");
655 break;
659 int pbc_dx_aiuc(const t_pbc *pbc,const rvec x1, const rvec x2, rvec dx)
661 int i,j,is;
662 rvec dx_start,trial;
663 real d2min,d2trial;
664 ivec ishift,ishift_start;
666 rvec_sub(x1,x2,dx);
667 clear_ivec(ishift);
669 switch (pbc->ePBCDX) {
670 case epbcdxRECTANGULAR:
671 for(i=0; i<DIM; i++) {
672 if (dx[i] > pbc->hbox_diag[i]) {
673 dx[i] -= pbc->fbox_diag[i];
674 ishift[i]--;
675 } else if (dx[i] <= pbc->mhbox_diag[i]) {
676 dx[i] += pbc->fbox_diag[i];
677 ishift[i]++;
680 break;
681 case epbcdxTRICLINIC:
682 /* For triclinic boxes the performance difference between
683 * if/else and two while loops is negligible.
684 * However, the while version can cause extreme delays
685 * before a simulation crashes due to large forces which
686 * can cause unlimited displacements.
687 * Also allowing multiple shifts would index fshift beyond bounds.
689 for(i=DIM-1; i>=1; i--) {
690 if (dx[i] > pbc->hbox_diag[i]) {
691 for (j=i; j>=0; j--)
692 dx[j] -= pbc->box[i][j];
693 ishift[i]--;
694 } else if (dx[i] <= pbc->mhbox_diag[i]) {
695 for (j=i; j>=0; j--)
696 dx[j] += pbc->box[i][j];
697 ishift[i]++;
700 /* Allow 2 shifts in x */
701 if (dx[XX] > pbc->hbox_diag[XX]) {
702 dx[XX] -= pbc->fbox_diag[XX];
703 ishift[XX]--;
704 if (dx[XX] > pbc->hbox_diag[XX]) {
705 dx[XX] -= pbc->fbox_diag[XX];
706 ishift[XX]--;
708 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
709 dx[XX] += pbc->fbox_diag[XX];
710 ishift[XX]++;
711 if (dx[XX] <= pbc->mhbox_diag[XX]) {
712 dx[XX] += pbc->fbox_diag[XX];
713 ishift[XX]++;
716 /* dx is the distance in a rectangular box */
717 d2min = norm2(dx);
718 if (d2min > pbc->max_cutoff2) {
719 copy_rvec(dx,dx_start);
720 copy_ivec(ishift,ishift_start);
721 d2min = norm2(dx);
722 /* Now try all possible shifts, when the distance is within max_cutoff
723 * it must be the shortest possible distance.
725 i = 0;
726 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
727 rvec_add(dx_start,pbc->tric_vec[i],trial);
728 d2trial = norm2(trial);
729 if (d2trial < d2min) {
730 copy_rvec(trial,dx);
731 ivec_add(ishift_start,pbc->tric_shift[i],ishift);
732 d2min = d2trial;
734 i++;
737 break;
738 case epbcdx2D_RECT:
739 for(i=0; i<DIM; i++) {
740 if (i != pbc->dim) {
741 if (dx[i] > pbc->hbox_diag[i]) {
742 dx[i] -= pbc->fbox_diag[i];
743 ishift[i]--;
744 } else if (dx[i] <= pbc->mhbox_diag[i]) {
745 dx[i] += pbc->fbox_diag[i];
746 ishift[i]++;
750 break;
751 case epbcdx2D_TRIC:
752 d2min = 0;
753 for(i=DIM-1; i>=1; i--) {
754 if (i != pbc->dim) {
755 if (dx[i] > pbc->hbox_diag[i]) {
756 for (j=i; j>=0; j--)
757 dx[j] -= pbc->box[i][j];
758 ishift[i]--;
759 } else if (dx[i] <= pbc->mhbox_diag[i]) {
760 for (j=i; j>=0; j--)
761 dx[j] += pbc->box[i][j];
762 ishift[i]++;
764 d2min += dx[i]*dx[i];
767 if (pbc->dim != XX) {
768 /* Allow 2 shifts in x */
769 if (dx[XX] > pbc->hbox_diag[XX]) {
770 dx[XX] -= pbc->fbox_diag[XX];
771 ishift[XX]--;
772 if (dx[XX] > pbc->hbox_diag[XX]) {
773 dx[XX] -= pbc->fbox_diag[XX];
774 ishift[XX]--;
776 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
777 dx[XX] += pbc->fbox_diag[XX];
778 ishift[XX]++;
779 if (dx[XX] <= pbc->mhbox_diag[XX]) {
780 dx[XX] += pbc->fbox_diag[XX];
781 ishift[XX]++;
784 d2min += dx[XX]*dx[XX];
786 if (d2min > pbc->max_cutoff2) {
787 copy_rvec(dx,dx_start);
788 copy_ivec(ishift,ishift_start);
789 /* Now try all possible shifts, when the distance is within max_cutoff
790 * it must be the shortest possible distance.
792 i = 0;
793 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
794 rvec_add(dx_start,pbc->tric_vec[i],trial);
795 d2trial = 0;
796 for(j=0; j<DIM; j++) {
797 if (j != pbc->dim) {
798 d2trial += trial[j]*trial[j];
801 if (d2trial < d2min) {
802 copy_rvec(trial,dx);
803 ivec_add(ishift_start,pbc->tric_shift[i],ishift);
804 d2min = d2trial;
806 i++;
809 break;
810 case epbcdx1D_RECT:
811 i = pbc->dim;
812 if (dx[i] > pbc->hbox_diag[i]) {
813 dx[i] -= pbc->fbox_diag[i];
814 ishift[i]--;
815 } else if (dx[i] <= pbc->mhbox_diag[i]) {
816 dx[i] += pbc->fbox_diag[i];
817 ishift[i]++;
819 break;
820 case epbcdx1D_TRIC:
821 i = pbc->dim;
822 if (dx[i] > pbc->hbox_diag[i]) {
823 rvec_dec(dx,pbc->box[i]);
824 ishift[i]--;
825 } else if (dx[i] <= pbc->mhbox_diag[i]) {
826 rvec_inc(dx,pbc->box[i]);
827 ishift[i]++;
829 break;
830 case epbcdxSCREW_RECT:
831 /* The shift definition requires x first */
832 if (dx[XX] > pbc->hbox_diag[XX]) {
833 dx[XX] -= pbc->fbox_diag[XX];
834 ishift[XX]--;
835 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
836 dx[XX] += pbc->fbox_diag[XX];
837 ishift[XX]++;
839 if (ishift[XX] == 1 || ishift[XX] == -1) {
840 /* Rotate around the x-axis in the middle of the box */
841 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
842 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
844 /* Normal pbc for y and z */
845 for(i=YY; i<=ZZ; i++) {
846 if (dx[i] > pbc->hbox_diag[i]) {
847 dx[i] -= pbc->fbox_diag[i];
848 ishift[i]--;
849 } else if (dx[i] <= pbc->mhbox_diag[i]) {
850 dx[i] += pbc->fbox_diag[i];
851 ishift[i]++;
854 break;
855 case epbcdxNOPBC:
856 case epbcdxUNSUPPORTED:
857 break;
858 default:
859 gmx_fatal(FARGS,"Internal error in pbc_dx_aiuc, set_pbc_dd or set_pbc has not been called");
860 break;
863 is = IVEC2IS(ishift);
864 if (debug)
866 range_check_mesg(is,0,SHIFTS,"PBC shift vector index range check.");
869 return is;
872 void pbc_dx_d(const t_pbc *pbc,const dvec x1, const dvec x2, dvec dx)
874 int i,j;
875 dvec dx_start,trial;
876 double d2min,d2trial;
877 bool bRot;
879 dvec_sub(x1,x2,dx);
881 switch (pbc->ePBCDX) {
882 case epbcdxRECTANGULAR:
883 case epbcdx2D_RECT:
884 for(i=0; i<DIM; i++) {
885 if (i != pbc->dim) {
886 while (dx[i] > pbc->hbox_diag[i]) {
887 dx[i] -= pbc->fbox_diag[i];
889 while (dx[i] <= pbc->mhbox_diag[i]) {
890 dx[i] += pbc->fbox_diag[i];
894 break;
895 case epbcdxTRICLINIC:
896 case epbcdx2D_TRIC:
897 d2min = 0;
898 for(i=DIM-1; i>=0; i--) {
899 if (i != pbc->dim) {
900 while (dx[i] > pbc->hbox_diag[i]) {
901 for (j=i; j>=0; j--)
902 dx[j] -= pbc->box[i][j];
904 while (dx[i] <= pbc->mhbox_diag[i]) {
905 for (j=i; j>=0; j--)
906 dx[j] += pbc->box[i][j];
908 d2min += dx[i]*dx[i];
911 if (d2min > pbc->max_cutoff2) {
912 copy_dvec(dx,dx_start);
913 /* Now try all possible shifts, when the distance is within max_cutoff
914 * it must be the shortest possible distance.
916 i = 0;
917 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
918 for(j=0; j<DIM; j++) {
919 trial[j] = dx_start[j] + pbc->tric_vec[i][j];
921 d2trial = 0;
922 for(j=0; j<DIM; j++) {
923 if (j != pbc->dim) {
924 d2trial += trial[j]*trial[j];
927 if (d2trial < d2min) {
928 copy_dvec(trial,dx);
929 d2min = d2trial;
931 i++;
934 break;
935 case epbcdxSCREW_RECT:
936 /* The shift definition requires x first */
937 bRot = FALSE;
938 while (dx[XX] > pbc->hbox_diag[XX]) {
939 dx[XX] -= pbc->fbox_diag[XX];
940 bRot = !bRot;
942 while (dx[XX] <= pbc->mhbox_diag[XX]) {
943 dx[XX] += pbc->fbox_diag[YY];
944 bRot = !bRot;
946 if (bRot) {
947 /* Rotate around the x-axis in the middle of the box */
948 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
949 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
951 /* Normal pbc for y and z */
952 for(i=YY; i<=ZZ; i++) {
953 while (dx[i] > pbc->hbox_diag[i]) {
954 dx[i] -= pbc->fbox_diag[i];
956 while (dx[i] <= pbc->mhbox_diag[i]) {
957 dx[i] += pbc->fbox_diag[i];
960 break;
961 case epbcdxNOPBC:
962 case epbcdxUNSUPPORTED:
963 break;
964 default:
965 gmx_fatal(FARGS,"Internal error in pbc_dx, set_pbc has not been called");
966 break;
970 bool image_rect(ivec xi,ivec xj,ivec box_size,real rlong2,int *shift,real *r2)
972 int m,t;
973 int dx,b,b_2;
974 real dxr,rij2;
976 rij2=0.0;
977 t=0;
978 for(m=0; (m<DIM); m++) {
979 dx=xi[m]-xj[m];
980 t*=DIM;
981 b=box_size[m];
982 b_2=b/2;
983 if (dx < -b_2) {
984 t+=2;
985 dx+=b;
987 else if (dx > b_2)
988 dx-=b;
989 else
990 t+=1;
991 dxr=dx;
992 rij2+=dxr*dxr;
993 if (rij2 >= rlong2)
994 return FALSE;
997 *shift = t;
998 *r2 = rij2;
999 return TRUE;
1002 bool image_cylindric(ivec xi,ivec xj,ivec box_size,real rlong2,
1003 int *shift,real *r2)
1005 int m,t;
1006 int dx,b,b_2;
1007 real dxr,rij2;
1009 rij2=0.0;
1010 t=0;
1011 for(m=0; (m<DIM); m++) {
1012 dx=xi[m]-xj[m];
1013 t*=DIM;
1014 b=box_size[m];
1015 b_2=b/2;
1016 if (dx < -b_2) {
1017 t+=2;
1018 dx+=b;
1020 else if (dx > b_2)
1021 dx-=b;
1022 else
1023 t+=1;
1025 dxr=dx;
1026 rij2+=dxr*dxr;
1027 if (m < ZZ) {
1028 if (rij2 >= rlong2)
1029 return FALSE;
1033 *shift = t;
1034 *r2 = rij2;
1035 return TRUE;
1038 void calc_shifts(matrix box,rvec shift_vec[])
1040 int k,l,m,d,n,test;
1042 n=0;
1043 for(m = -D_BOX_Z; m <= D_BOX_Z; m++)
1044 for(l = -D_BOX_Y; l <= D_BOX_Y; l++)
1045 for(k = -D_BOX_X; k <= D_BOX_X; k++,n++) {
1046 test = XYZ2IS(k,l,m);
1047 if (n != test)
1048 gmx_incons("inconsistent shift numbering");
1049 for(d = 0; d < DIM; d++)
1050 shift_vec[n][d] = k*box[XX][d] + l*box[YY][d] + m*box[ZZ][d];
1054 void calc_box_center(int ecenter,matrix box,rvec box_center)
1056 int d,m;
1058 clear_rvec(box_center);
1059 switch (ecenter) {
1060 case ecenterTRIC:
1061 for(m=0; (m<DIM); m++)
1062 for(d=0; d<DIM; d++)
1063 box_center[d] += 0.5*box[m][d];
1064 break;
1065 case ecenterRECT:
1066 for(d=0; d<DIM; d++)
1067 box_center[d] = 0.5*box[d][d];
1068 break;
1069 case ecenterZERO:
1070 break;
1071 default:
1072 gmx_fatal(FARGS,"Unsupported value %d for ecenter",ecenter);
1076 void calc_triclinic_images(matrix box,rvec img[])
1078 int i;
1080 /* Calculate 3 adjacent images in the xy-plane */
1081 copy_rvec(box[0],img[0]);
1082 copy_rvec(box[1],img[1]);
1083 if (img[1][XX] < 0)
1084 svmul(-1,img[1],img[1]);
1085 rvec_sub(img[1],img[0],img[2]);
1087 /* Get the next 3 in the xy-plane as mirror images */
1088 for(i=0; i<3; i++)
1089 svmul(-1,img[i],img[3+i]);
1091 /* Calculate the first 4 out of xy-plane images */
1092 copy_rvec(box[2],img[6]);
1093 if (img[6][XX] < 0)
1094 svmul(-1,img[6],img[6]);
1095 for(i=0; i<3; i++)
1096 rvec_add(img[6],img[i+1],img[7+i]);
1098 /* Mirror the last 4 from the previous in opposite rotation */
1099 for(i=0; i<4; i++)
1100 svmul(-1,img[6 + (2+i) % 4],img[10+i]);
1103 void calc_compact_unitcell_vertices(int ecenter,matrix box,rvec vert[])
1105 rvec img[NTRICIMG],box_center;
1106 int n,i,j,tmp[4],d;
1108 calc_triclinic_images(box,img);
1110 n=0;
1111 for(i=2; i<=5; i+=3) {
1112 tmp[0] = i-1;
1113 if (i==2)
1114 tmp[1] = 8;
1115 else
1116 tmp[1] = 6;
1117 tmp[2] = (i+1) % 6;
1118 tmp[3] = tmp[1]+4;
1119 for(j=0; j<4; j++) {
1120 for(d=0; d<DIM; d++)
1121 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1122 n++;
1125 for(i=7; i<=13; i+=6) {
1126 tmp[0] = (i-7)/2;
1127 tmp[1] = tmp[0]+1;
1128 if (i==7)
1129 tmp[2] = 8;
1130 else
1131 tmp[2] = 10;
1132 tmp[3] = i-1;
1133 for(j=0; j<4; j++) {
1134 for(d=0; d<DIM; d++)
1135 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1136 n++;
1139 for(i=9; i<=11; i+=2) {
1140 if (i==9)
1141 tmp[0] = 3;
1142 else
1143 tmp[0] = 0;
1144 tmp[1] = tmp[0]+1;
1145 if (i==9)
1146 tmp[2] = 6;
1147 else
1148 tmp[2] = 12;
1149 tmp[3] = i-1;
1150 for(j=0; j<4; j++) {
1151 for(d=0; d<DIM; d++)
1152 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1153 n++;
1157 calc_box_center(ecenter,box,box_center);
1158 for(i=0; i<NCUCVERT; i++)
1159 for(d=0; d<DIM; d++)
1160 vert[i][d] = vert[i][d]*0.25+box_center[d];
1163 int *compact_unitcell_edges()
1165 /* this is an index in vert[] (see calc_box_vertices) */
1166 static int edge[NCUCEDGE*2];
1167 static int hexcon[24] = { 0,9, 1,19, 2,15, 3,21,
1168 4,17, 5,11, 6,23, 7,13,
1169 8,20, 10,18, 12,16, 14,22 };
1170 int e,i,j;
1171 bool bFirst = TRUE;
1173 if (bFirst) {
1174 e = 0;
1175 for(i=0; i<6; i++)
1176 for(j=0; j<4; j++) {
1177 edge[e++] = 4*i + j;
1178 edge[e++] = 4*i + (j+1) % 4;
1180 for(i=0; i<12*2; i++)
1181 edge[e++] = hexcon[i];
1183 bFirst = FALSE;
1186 return edge;
1189 void put_atom_in_box(matrix box,rvec x)
1191 int i,m,d;
1193 for(m=DIM-1; m>=0; m--) {
1194 while (x[m] < 0)
1195 for(d=0; d<=m; d++)
1196 x[d] += box[m][d];
1197 while (x[m] >= box[m][m])
1198 for(d=0; d<=m; d++)
1199 x[d] -= box[m][d];
1203 void put_atoms_in_box(matrix box,int natoms,rvec x[])
1205 int i,m,d;
1207 for(i=0; (i<natoms); i++)
1208 put_atom_in_box(box,x[i]);
1211 void put_atoms_in_triclinic_unitcell(int ecenter,matrix box,
1212 int natoms,rvec x[])
1214 rvec box_center,shift_center;
1215 real shm01,shm02,shm12,shift;
1216 int i,m,d;
1218 calc_box_center(ecenter,box,box_center);
1220 /* The product of matrix shm with a coordinate gives the shift vector
1221 which is required determine the periodic cell position */
1222 shm01 = box[1][0]/box[1][1];
1223 shm02 = (box[1][1]*box[2][0] - box[2][1]*box[1][0])/(box[1][1]*box[2][2]);
1224 shm12 = box[2][1]/box[2][2];
1226 clear_rvec(shift_center);
1227 for(d=0; d<DIM; d++)
1228 rvec_inc(shift_center,box[d]);
1229 svmul(0.5,shift_center,shift_center);
1230 rvec_sub(box_center,shift_center,shift_center);
1232 shift_center[0] = shm01*shift_center[1] + shm02*shift_center[2];
1233 shift_center[1] = shm12*shift_center[2];
1234 shift_center[2] = 0;
1236 for(i=0; (i<natoms); i++)
1237 for(m=DIM-1; m>=0; m--) {
1238 shift = shift_center[m];
1239 if (m == 0) {
1240 shift += shm01*x[i][1] + shm02*x[i][2];
1241 } else if (m == 1) {
1242 shift += shm12*x[i][2];
1244 while (x[i][m]-shift < 0)
1245 for(d=0; d<=m; d++)
1246 x[i][d] += box[m][d];
1247 while (x[i][m]-shift >= box[m][m])
1248 for(d=0; d<=m; d++)
1249 x[i][d] -= box[m][d];
1253 const char *
1254 put_atoms_in_compact_unitcell(int ePBC,int ecenter,matrix box,
1255 int natoms,rvec x[])
1257 t_pbc pbc;
1258 rvec box_center,dx;
1259 int i;
1261 set_pbc(&pbc,ePBC,box);
1262 calc_box_center(ecenter,box,box_center);
1263 for(i=0; i<natoms; i++) {
1264 pbc_dx(&pbc,x[i],box_center,dx);
1265 rvec_add(box_center,dx,x[i]);
1268 return pbc.bLimitDistance ?
1269 "WARNING: Could not put all atoms in the compact unitcell\n"
1270 : NULL;