2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team,
6 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012,2013, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
51 #include "gmx_fatal.h"
53 #include "gmx_omp_nthreads.h"
55 /* Skip 0 so we have more chance of detecting if we forgot to call set_pbc. */
56 enum { epbcdxRECTANGULAR=1, epbcdxTRICLINIC,
57 epbcdx2D_RECT, epbcdx2D_TRIC,
58 epbcdx1D_RECT, epbcdx1D_TRIC,
59 epbcdxSCREW_RECT, epbcdxSCREW_TRIC,
60 epbcdxNOPBC, epbcdxUNSUPPORTED };
62 /* Margin factor for error message and correction if the box is too skewed */
63 #define BOX_MARGIN 1.0010
64 #define BOX_MARGIN_CORRECT 1.0005
66 int ePBC2npbcdim(int ePBC)
71 case epbcXYZ: npbcdim = 3; break;
72 case epbcXY: npbcdim = 2; break;
73 case epbcSCREW: npbcdim = 3; break;
74 case epbcNONE: npbcdim = 0; break;
75 default: gmx_fatal(FARGS,"Unknown ePBC=%d in ePBC2npbcdim",ePBC);
81 int inputrec2nboundeddim(t_inputrec *ir)
83 if (ir->nwall == 2 && ir->ePBC == epbcXY)
89 return ePBC2npbcdim(ir->ePBC);
93 void dump_pbc(FILE *fp,t_pbc *pbc)
97 fprintf(fp,"ePBCDX = %d\n",pbc->ePBCDX);
98 pr_rvecs(fp,0,"box",pbc->box,DIM);
99 pr_rvecs(fp,0,"fbox_diag",&pbc->fbox_diag,1);
100 pr_rvecs(fp,0,"hbox_diag",&pbc->hbox_diag,1);
101 pr_rvecs(fp,0,"mhbox_diag",&pbc->mhbox_diag,1);
102 rvec_add(pbc->hbox_diag,pbc->mhbox_diag,sum_box);
103 pr_rvecs(fp,0,"sum of the above two",&sum_box,1);
104 fprintf(fp,"max_cutoff2 = %g\n",pbc->max_cutoff2);
105 fprintf(fp,"bLimitDistance = %s\n",EBOOL(pbc->bLimitDistance));
106 fprintf(fp,"limit_distance2 = %g\n",pbc->limit_distance2);
107 fprintf(fp,"ntric_vec = %d\n",pbc->ntric_vec);
108 if (pbc->ntric_vec > 0) {
109 pr_ivecs(fp,0,"tric_shift",pbc->tric_shift,pbc->ntric_vec,FALSE);
110 pr_rvecs(fp,0,"tric_vec",pbc->tric_vec,pbc->ntric_vec);
114 const char *check_box(int ePBC,matrix box)
119 ePBC = guess_ePBC(box);
121 if (ePBC == epbcNONE)
124 if ((box[XX][YY] != 0) || (box[XX][ZZ] != 0) || (box[YY][ZZ] != 0)) {
125 ptr = "Only triclinic boxes with the first vector parallel to the x-axis and the second vector in the xy-plane are supported.";
126 } else if (ePBC == epbcSCREW && (box[YY][XX] != 0 || box[ZZ][XX] != 0)) {
127 ptr = "The unit cell can not have off-diagonal x-components with screw pbc";
128 } else if (fabs(box[YY][XX]) > BOX_MARGIN*0.5*box[XX][XX] ||
130 (fabs(box[ZZ][XX]) > BOX_MARGIN*0.5*box[XX][XX] ||
131 fabs(box[ZZ][YY]) > BOX_MARGIN*0.5*box[YY][YY]))) {
132 ptr = "Triclinic box is too skewed.";
140 real max_cutoff2(int ePBC,matrix box)
144 /* Physical limitation of the cut-off
145 * by half the length of the shortest box vector.
147 min_hv2 = min(0.25*norm2(box[XX]),0.25*norm2(box[YY]));
149 min_hv2 = min(min_hv2,0.25*norm2(box[ZZ]));
151 /* Limitation to the smallest diagonal element due to optimizations:
152 * checking only linear combinations of single box-vectors (2 in x)
153 * in the grid search and pbc_dx is a lot faster
154 * than checking all possible combinations.
156 if (ePBC == epbcXY) {
157 min_ss = min(box[XX][XX],box[YY][YY]);
159 min_ss = min(box[XX][XX],min(box[YY][YY]-fabs(box[ZZ][YY]),box[ZZ][ZZ]));
162 return min(min_hv2,min_ss*min_ss);
165 /* this one is mostly harmless... */
166 static gmx_bool bWarnedGuess=FALSE;
168 int guess_ePBC(matrix box)
172 if (box[XX][XX]>0 && box[YY][YY]>0 && box[ZZ][ZZ]>0) {
174 } else if (box[XX][XX]>0 && box[YY][YY]>0 && box[ZZ][ZZ]==0) {
176 } else if (box[XX][XX]==0 && box[YY][YY]==0 && box[ZZ][ZZ]==0) {
180 fprintf(stderr,"WARNING: Unsupported box diagonal %f %f %f, "
181 "will not use periodic boundary conditions\n\n",
182 box[XX][XX],box[YY][YY],box[ZZ][ZZ]);
189 fprintf(debug,"Guessed pbc = %s from the box matrix\n",epbc_names[ePBC]);
194 static int correct_box_elem(FILE *fplog,int step,tensor box,int v,int d)
196 int shift,maxshift=10;
200 /* correct elem d of vector v with vector d */
201 while (box[v][d] > BOX_MARGIN_CORRECT*0.5*box[d][d]) {
203 fprintf(fplog,"Step %d: correcting invalid box:\n",step);
204 pr_rvecs(fplog,0,"old box",box,DIM);
206 rvec_dec(box[v],box[d]);
209 pr_rvecs(fplog,0,"new box",box,DIM);
211 if (shift <= -maxshift)
213 "Box was shifted at least %d times. Please see log-file.",
216 while (box[v][d] < -BOX_MARGIN_CORRECT*0.5*box[d][d]) {
218 fprintf(fplog,"Step %d: correcting invalid box:\n",step);
219 pr_rvecs(fplog,0,"old box",box,DIM);
221 rvec_inc(box[v],box[d]);
224 pr_rvecs(fplog,0,"new box",box,DIM);
226 if (shift >= maxshift)
228 "Box was shifted at least %d times. Please see log-file.",
235 gmx_bool correct_box(FILE *fplog,int step,tensor box,t_graph *graph)
240 /* check if the box still obeys the restrictions, if not, correct it */
241 zy = correct_box_elem(fplog,step,box,ZZ,YY);
242 zx = correct_box_elem(fplog,step,box,ZZ,XX);
243 yx = correct_box_elem(fplog,step,box,YY,XX);
245 bCorrected = (zy || zx || yx);
247 if (bCorrected && graph) {
248 /* correct the graph */
249 for(i=graph->at_start; i<graph->at_end; i++) {
250 graph->ishift[i][YY] -= graph->ishift[i][ZZ]*zy;
251 graph->ishift[i][XX] -= graph->ishift[i][ZZ]*zx;
252 graph->ishift[i][XX] -= graph->ishift[i][YY]*yx;
259 int ndof_com(t_inputrec *ir)
269 n = (ir->nwall == 0 ? 3 : 2);
275 gmx_incons("Unknown pbc in calc_nrdf");
281 static void low_set_pbc(t_pbc *pbc,int ePBC,ivec *dd_nc,matrix box)
283 int order[5]={0,-1,1,-2,2};
284 int ii,jj,kk,i,j,k,d,dd,jc,kc,npbcdim,shift;
286 real d2old,d2new,d2new_c;
291 pbc->ndim_ePBC = ePBC2npbcdim(ePBC);
293 copy_mat(box,pbc->box);
294 pbc->bLimitDistance = FALSE;
295 pbc->max_cutoff2 = 0;
298 for(i=0; (i<DIM); i++) {
299 pbc->fbox_diag[i] = box[i][i];
300 pbc->hbox_diag[i] = pbc->fbox_diag[i]*0.5;
301 pbc->mhbox_diag[i] = -pbc->hbox_diag[i];
304 ptr = check_box(ePBC,box);
305 if (ePBC == epbcNONE) {
306 pbc->ePBCDX = epbcdxNOPBC;
308 fprintf(stderr, "Warning: %s\n",ptr);
309 pr_rvecs(stderr,0," Box",box,DIM);
310 fprintf(stderr, " Can not fix pbc.\n");
311 pbc->ePBCDX = epbcdxUNSUPPORTED;
312 pbc->bLimitDistance = TRUE;
313 pbc->limit_distance2 = 0;
315 if (ePBC == epbcSCREW && dd_nc) {
316 /* This combinated should never appear here */
317 gmx_incons("low_set_pbc called with screw pbc and dd_nc != NULL");
321 for(i=0; i<DIM; i++) {
322 if ((dd_nc && (*dd_nc)[i] > 1) || (ePBC == epbcXY && i == ZZ)) {
331 /* 1D pbc is not an mdp option and it is therefore only used
332 * with single shifts.
334 pbc->ePBCDX = epbcdx1D_RECT;
338 for(i=0; i<pbc->dim; i++)
339 if (pbc->box[pbc->dim][i] != 0)
340 pbc->ePBCDX = epbcdx1D_TRIC;
343 pbc->ePBCDX = epbcdx2D_RECT;
350 if (pbc->box[i][j] != 0)
351 pbc->ePBCDX = epbcdx2D_TRIC;
354 if (ePBC != epbcSCREW) {
355 if (TRICLINIC(box)) {
356 pbc->ePBCDX = epbcdxTRICLINIC;
358 pbc->ePBCDX = epbcdxRECTANGULAR;
361 pbc->ePBCDX = (box[ZZ][YY]==0 ? epbcdxSCREW_RECT : epbcdxSCREW_TRIC);
362 if (pbc->ePBCDX == epbcdxSCREW_TRIC) {
364 "Screw pbc is not yet implemented for triclinic boxes.\n"
365 "Can not fix pbc.\n");
366 pbc->ePBCDX = epbcdxUNSUPPORTED;
371 gmx_fatal(FARGS,"Incorrect number of pbc dimensions with DD: %d",
374 pbc->max_cutoff2 = max_cutoff2(ePBC,box);
376 if (pbc->ePBCDX == epbcdxTRICLINIC ||
377 pbc->ePBCDX == epbcdx2D_TRIC ||
378 pbc->ePBCDX == epbcdxSCREW_TRIC) {
380 pr_rvecs(debug,0,"Box",box,DIM);
381 fprintf(debug,"max cutoff %.3f\n",sqrt(pbc->max_cutoff2));
384 /* We will only use single shifts, but we will check a few
385 * more shifts to see if there is a limiting distance
386 * above which we can not be sure of the correct distance.
388 for(kk=0; kk<5; kk++) {
390 if (!bPBC[ZZ] && k != 0)
392 for(jj=0; jj<5; jj++) {
394 if (!bPBC[YY] && j != 0)
396 for(ii=0; ii<3; ii++) {
398 if (!bPBC[XX] && i != 0)
400 /* A shift is only useful when it is trilinic */
401 if (j != 0 || k != 0) {
404 for(d=0; d<DIM; d++) {
405 trial[d] = i*box[XX][d] + j*box[YY][d] + k*box[ZZ][d];
406 /* Choose the vector within the brick around 0,0,0 that
407 * will become the shortest due to shift try.
414 pos[d] = min( pbc->hbox_diag[d],-trial[d]);
416 pos[d] = max(-pbc->hbox_diag[d],-trial[d]);
418 d2old += sqr(pos[d]);
419 d2new += sqr(pos[d] + trial[d]);
421 if (BOX_MARGIN*d2new < d2old) {
422 if (j < -1 || j > 1 || k < -1 || k > 1) {
423 /* Check if there is a single shift vector
424 * that decreases this distance even more.
434 d2new_c += sqr(pos[d] + trial[d]
435 - jc*box[YY][d] - kc*box[ZZ][d]);
436 if (d2new_c > BOX_MARGIN*d2new) {
437 /* Reject this shift vector, as there is no a priori limit
438 * to the number of shifts that decrease distances.
440 if (!pbc->bLimitDistance || d2new < pbc->limit_distance2)
441 pbc->limit_distance2 = d2new;
442 pbc->bLimitDistance = TRUE;
445 /* Check if shifts with one box vector less do better */
447 for(dd=0; dd<DIM; dd++) {
448 shift = (dd==0 ? i : (dd==1 ? j : k));
452 d2new_c += sqr(pos[d] + trial[d] - shift*box[dd][d]);
453 if (d2new_c <= BOX_MARGIN*d2new)
458 /* Accept this shift vector. */
459 if (pbc->ntric_vec >= MAX_NTRICVEC) {
460 fprintf(stderr,"\nWARNING: Found more than %d triclinic correction vectors, ignoring some.\n"
461 " There is probably something wrong with your box.\n",MAX_NTRICVEC);
462 pr_rvecs(stderr,0," Box",box,DIM);
464 copy_rvec(trial,pbc->tric_vec[pbc->ntric_vec]);
465 pbc->tric_shift[pbc->ntric_vec][XX] = i;
466 pbc->tric_shift[pbc->ntric_vec][YY] = j;
467 pbc->tric_shift[pbc->ntric_vec][ZZ] = k;
473 fprintf(debug," tricvec %2d = %2d %2d %2d %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
474 pbc->ntric_vec,i,j,k,
475 sqrt(d2old),sqrt(d2new),
476 trial[XX],trial[YY],trial[ZZ],
477 pos[XX],pos[YY],pos[ZZ]);
488 void set_pbc(t_pbc *pbc,int ePBC,matrix box)
491 ePBC = guess_ePBC(box);
493 low_set_pbc(pbc,ePBC,NULL,box);
496 t_pbc *set_pbc_dd(t_pbc *pbc,int ePBC,
497 gmx_domdec_t *dd,gmx_bool bSingleDir,matrix box)
505 if (ePBC == epbcSCREW && dd->nc[XX] > 1) {
506 /* The rotation has been taken care of during coordinate communication */
510 for(i=0; i<DIM; i++) {
511 if (dd->nc[i] <= (bSingleDir ? 1 : 2)) {
513 if (!(ePBC == epbcXY && i == ZZ))
522 low_set_pbc(pbc,ePBC,npbcdim<DIM ? &nc2 : NULL,box);
524 return (npbcdim > 0 ? pbc : NULL);
527 void pbc_dx(const t_pbc *pbc,const rvec x1, const rvec x2, rvec dx)
536 switch (pbc->ePBCDX) {
537 case epbcdxRECTANGULAR:
538 for(i=0; i<DIM; i++) {
539 while (dx[i] > pbc->hbox_diag[i]) {
540 dx[i] -= pbc->fbox_diag[i];
542 while (dx[i] <= pbc->mhbox_diag[i]) {
543 dx[i] += pbc->fbox_diag[i];
547 case epbcdxTRICLINIC:
548 for(i=DIM-1; i>=0; i--) {
549 while (dx[i] > pbc->hbox_diag[i]) {
551 dx[j] -= pbc->box[i][j];
553 while (dx[i] <= pbc->mhbox_diag[i]) {
555 dx[j] += pbc->box[i][j];
558 /* dx is the distance in a rectangular box */
560 if (d2min > pbc->max_cutoff2) {
561 copy_rvec(dx,dx_start);
563 /* Now try all possible shifts, when the distance is within max_cutoff
564 * it must be the shortest possible distance.
567 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
568 rvec_add(dx_start,pbc->tric_vec[i],trial);
569 d2trial = norm2(trial);
570 if (d2trial < d2min) {
579 for(i=0; i<DIM; i++) {
581 while (dx[i] > pbc->hbox_diag[i]) {
582 dx[i] -= pbc->fbox_diag[i];
584 while (dx[i] <= pbc->mhbox_diag[i]) {
585 dx[i] += pbc->fbox_diag[i];
592 for(i=DIM-1; i>=0; i--) {
594 while (dx[i] > pbc->hbox_diag[i]) {
596 dx[j] -= pbc->box[i][j];
598 while (dx[i] <= pbc->mhbox_diag[i]) {
600 dx[j] += pbc->box[i][j];
602 d2min += dx[i]*dx[i];
605 if (d2min > pbc->max_cutoff2) {
606 copy_rvec(dx,dx_start);
608 /* Now try all possible shifts, when the distance is within max_cutoff
609 * it must be the shortest possible distance.
612 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
613 rvec_add(dx_start,pbc->tric_vec[i],trial);
615 for(j=0; j<DIM; j++) {
617 d2trial += trial[j]*trial[j];
620 if (d2trial < d2min) {
628 case epbcdxSCREW_RECT:
629 /* The shift definition requires x first */
631 while (dx[XX] > pbc->hbox_diag[XX]) {
632 dx[XX] -= pbc->fbox_diag[XX];
635 while (dx[XX] <= pbc->mhbox_diag[XX]) {
636 dx[XX] += pbc->fbox_diag[YY];
640 /* Rotate around the x-axis in the middle of the box */
641 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
642 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
644 /* Normal pbc for y and z */
645 for(i=YY; i<=ZZ; i++) {
646 while (dx[i] > pbc->hbox_diag[i]) {
647 dx[i] -= pbc->fbox_diag[i];
649 while (dx[i] <= pbc->mhbox_diag[i]) {
650 dx[i] += pbc->fbox_diag[i];
655 case epbcdxUNSUPPORTED:
658 gmx_fatal(FARGS,"Internal error in pbc_dx, set_pbc has not been called");
663 int pbc_dx_aiuc(const t_pbc *pbc,const rvec x1, const rvec x2, rvec dx)
668 ivec ishift,ishift_start;
673 switch (pbc->ePBCDX) {
674 case epbcdxRECTANGULAR:
675 for(i=0; i<DIM; i++) {
676 if (dx[i] > pbc->hbox_diag[i]) {
677 dx[i] -= pbc->fbox_diag[i];
679 } else if (dx[i] <= pbc->mhbox_diag[i]) {
680 dx[i] += pbc->fbox_diag[i];
685 case epbcdxTRICLINIC:
686 /* For triclinic boxes the performance difference between
687 * if/else and two while loops is negligible.
688 * However, the while version can cause extreme delays
689 * before a simulation crashes due to large forces which
690 * can cause unlimited displacements.
691 * Also allowing multiple shifts would index fshift beyond bounds.
693 for(i=DIM-1; i>=1; i--) {
694 if (dx[i] > pbc->hbox_diag[i]) {
696 dx[j] -= pbc->box[i][j];
698 } else if (dx[i] <= pbc->mhbox_diag[i]) {
700 dx[j] += pbc->box[i][j];
704 /* Allow 2 shifts in x */
705 if (dx[XX] > pbc->hbox_diag[XX]) {
706 dx[XX] -= pbc->fbox_diag[XX];
708 if (dx[XX] > pbc->hbox_diag[XX]) {
709 dx[XX] -= pbc->fbox_diag[XX];
712 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
713 dx[XX] += pbc->fbox_diag[XX];
715 if (dx[XX] <= pbc->mhbox_diag[XX]) {
716 dx[XX] += pbc->fbox_diag[XX];
720 /* dx is the distance in a rectangular box */
722 if (d2min > pbc->max_cutoff2) {
723 copy_rvec(dx,dx_start);
724 copy_ivec(ishift,ishift_start);
726 /* Now try all possible shifts, when the distance is within max_cutoff
727 * it must be the shortest possible distance.
730 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
731 rvec_add(dx_start,pbc->tric_vec[i],trial);
732 d2trial = norm2(trial);
733 if (d2trial < d2min) {
735 ivec_add(ishift_start,pbc->tric_shift[i],ishift);
743 for(i=0; i<DIM; i++) {
745 if (dx[i] > pbc->hbox_diag[i]) {
746 dx[i] -= pbc->fbox_diag[i];
748 } else if (dx[i] <= pbc->mhbox_diag[i]) {
749 dx[i] += pbc->fbox_diag[i];
757 for(i=DIM-1; i>=1; i--) {
759 if (dx[i] > pbc->hbox_diag[i]) {
761 dx[j] -= pbc->box[i][j];
763 } else if (dx[i] <= pbc->mhbox_diag[i]) {
765 dx[j] += pbc->box[i][j];
768 d2min += dx[i]*dx[i];
771 if (pbc->dim != XX) {
772 /* Allow 2 shifts in x */
773 if (dx[XX] > pbc->hbox_diag[XX]) {
774 dx[XX] -= pbc->fbox_diag[XX];
776 if (dx[XX] > pbc->hbox_diag[XX]) {
777 dx[XX] -= pbc->fbox_diag[XX];
780 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
781 dx[XX] += pbc->fbox_diag[XX];
783 if (dx[XX] <= pbc->mhbox_diag[XX]) {
784 dx[XX] += pbc->fbox_diag[XX];
788 d2min += dx[XX]*dx[XX];
790 if (d2min > pbc->max_cutoff2) {
791 copy_rvec(dx,dx_start);
792 copy_ivec(ishift,ishift_start);
793 /* Now try all possible shifts, when the distance is within max_cutoff
794 * it must be the shortest possible distance.
797 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
798 rvec_add(dx_start,pbc->tric_vec[i],trial);
800 for(j=0; j<DIM; j++) {
802 d2trial += trial[j]*trial[j];
805 if (d2trial < d2min) {
807 ivec_add(ishift_start,pbc->tric_shift[i],ishift);
816 if (dx[i] > pbc->hbox_diag[i]) {
817 dx[i] -= pbc->fbox_diag[i];
819 } else if (dx[i] <= pbc->mhbox_diag[i]) {
820 dx[i] += pbc->fbox_diag[i];
826 if (dx[i] > pbc->hbox_diag[i]) {
827 rvec_dec(dx,pbc->box[i]);
829 } else if (dx[i] <= pbc->mhbox_diag[i]) {
830 rvec_inc(dx,pbc->box[i]);
834 case epbcdxSCREW_RECT:
835 /* The shift definition requires x first */
836 if (dx[XX] > pbc->hbox_diag[XX]) {
837 dx[XX] -= pbc->fbox_diag[XX];
839 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
840 dx[XX] += pbc->fbox_diag[XX];
843 if (ishift[XX] == 1 || ishift[XX] == -1) {
844 /* Rotate around the x-axis in the middle of the box */
845 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
846 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
848 /* Normal pbc for y and z */
849 for(i=YY; i<=ZZ; i++) {
850 if (dx[i] > pbc->hbox_diag[i]) {
851 dx[i] -= pbc->fbox_diag[i];
853 } else if (dx[i] <= pbc->mhbox_diag[i]) {
854 dx[i] += pbc->fbox_diag[i];
860 case epbcdxUNSUPPORTED:
863 gmx_fatal(FARGS,"Internal error in pbc_dx_aiuc, set_pbc_dd or set_pbc has not been called");
867 is = IVEC2IS(ishift);
870 range_check_mesg(is,0,SHIFTS,"PBC shift vector index range check.");
876 void pbc_dx_d(const t_pbc *pbc,const dvec x1, const dvec x2, dvec dx)
880 double d2min,d2trial;
885 switch (pbc->ePBCDX) {
886 case epbcdxRECTANGULAR:
888 for(i=0; i<DIM; i++) {
890 while (dx[i] > pbc->hbox_diag[i]) {
891 dx[i] -= pbc->fbox_diag[i];
893 while (dx[i] <= pbc->mhbox_diag[i]) {
894 dx[i] += pbc->fbox_diag[i];
899 case epbcdxTRICLINIC:
902 for(i=DIM-1; i>=0; i--) {
904 while (dx[i] > pbc->hbox_diag[i]) {
906 dx[j] -= pbc->box[i][j];
908 while (dx[i] <= pbc->mhbox_diag[i]) {
910 dx[j] += pbc->box[i][j];
912 d2min += dx[i]*dx[i];
915 if (d2min > pbc->max_cutoff2) {
916 copy_dvec(dx,dx_start);
917 /* Now try all possible shifts, when the distance is within max_cutoff
918 * it must be the shortest possible distance.
921 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
922 for(j=0; j<DIM; j++) {
923 trial[j] = dx_start[j] + pbc->tric_vec[i][j];
926 for(j=0; j<DIM; j++) {
928 d2trial += trial[j]*trial[j];
931 if (d2trial < d2min) {
939 case epbcdxSCREW_RECT:
940 /* The shift definition requires x first */
942 while (dx[XX] > pbc->hbox_diag[XX]) {
943 dx[XX] -= pbc->fbox_diag[XX];
946 while (dx[XX] <= pbc->mhbox_diag[XX]) {
947 dx[XX] += pbc->fbox_diag[YY];
951 /* Rotate around the x-axis in the middle of the box */
952 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
953 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
955 /* Normal pbc for y and z */
956 for(i=YY; i<=ZZ; i++) {
957 while (dx[i] > pbc->hbox_diag[i]) {
958 dx[i] -= pbc->fbox_diag[i];
960 while (dx[i] <= pbc->mhbox_diag[i]) {
961 dx[i] += pbc->fbox_diag[i];
966 case epbcdxUNSUPPORTED:
969 gmx_fatal(FARGS,"Internal error in pbc_dx, set_pbc has not been called");
974 gmx_bool image_rect(ivec xi,ivec xj,ivec box_size,real rlong2,int *shift,real *r2)
982 for(m=0; (m<DIM); m++) {
1006 gmx_bool image_cylindric(ivec xi,ivec xj,ivec box_size,real rlong2,
1007 int *shift,real *r2)
1015 for(m=0; (m<DIM); m++) {
1042 void calc_shifts(matrix box,rvec shift_vec[])
1047 for(m = -D_BOX_Z; m <= D_BOX_Z; m++)
1048 for(l = -D_BOX_Y; l <= D_BOX_Y; l++)
1049 for(k = -D_BOX_X; k <= D_BOX_X; k++,n++) {
1050 test = XYZ2IS(k,l,m);
1052 gmx_incons("inconsistent shift numbering");
1053 for(d = 0; d < DIM; d++)
1054 shift_vec[n][d] = k*box[XX][d] + l*box[YY][d] + m*box[ZZ][d];
1058 void calc_box_center(int ecenter,matrix box,rvec box_center)
1062 clear_rvec(box_center);
1065 for(m=0; (m<DIM); m++)
1066 for(d=0; d<DIM; d++)
1067 box_center[d] += 0.5*box[m][d];
1070 for(d=0; d<DIM; d++)
1071 box_center[d] = 0.5*box[d][d];
1076 gmx_fatal(FARGS,"Unsupported value %d for ecenter",ecenter);
1080 void calc_triclinic_images(matrix box,rvec img[])
1084 /* Calculate 3 adjacent images in the xy-plane */
1085 copy_rvec(box[0],img[0]);
1086 copy_rvec(box[1],img[1]);
1088 svmul(-1,img[1],img[1]);
1089 rvec_sub(img[1],img[0],img[2]);
1091 /* Get the next 3 in the xy-plane as mirror images */
1093 svmul(-1,img[i],img[3+i]);
1095 /* Calculate the first 4 out of xy-plane images */
1096 copy_rvec(box[2],img[6]);
1098 svmul(-1,img[6],img[6]);
1100 rvec_add(img[6],img[i+1],img[7+i]);
1102 /* Mirror the last 4 from the previous in opposite rotation */
1104 svmul(-1,img[6 + (2+i) % 4],img[10+i]);
1107 void calc_compact_unitcell_vertices(int ecenter,matrix box,rvec vert[])
1109 rvec img[NTRICIMG],box_center;
1112 calc_triclinic_images(box,img);
1115 for(i=2; i<=5; i+=3) {
1123 for(j=0; j<4; j++) {
1124 for(d=0; d<DIM; d++)
1125 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1129 for(i=7; i<=13; i+=6) {
1137 for(j=0; j<4; j++) {
1138 for(d=0; d<DIM; d++)
1139 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1143 for(i=9; i<=11; i+=2) {
1154 for(j=0; j<4; j++) {
1155 for(d=0; d<DIM; d++)
1156 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1161 calc_box_center(ecenter,box,box_center);
1162 for(i=0; i<NCUCVERT; i++)
1163 for(d=0; d<DIM; d++)
1164 vert[i][d] = vert[i][d]*0.25+box_center[d];
1167 int *compact_unitcell_edges()
1169 /* this is an index in vert[] (see calc_box_vertices) */
1170 /*static int edge[NCUCEDGE*2];*/
1172 static const int hexcon[24] = { 0,9, 1,19, 2,15, 3,21,
1173 4,17, 5,11, 6,23, 7,13,
1174 8,20, 10,18, 12,16, 14,22 };
1176 gmx_bool bFirst = TRUE;
1178 snew(edge,NCUCEDGE*2);
1183 for(j=0; j<4; j++) {
1184 edge[e++] = 4*i + j;
1185 edge[e++] = 4*i + (j+1) % 4;
1187 for(i=0; i<12*2; i++)
1188 edge[e++] = hexcon[i];
1196 void put_atoms_in_box_omp(int ePBC,matrix box,int natoms,rvec x[])
1199 nth = gmx_omp_nthreads_get(emntDefault);
1201 #pragma omp parallel for num_threads(nth) schedule(static)
1202 for(t=0; t<nth; t++)
1206 offset = (natoms*t )/nth;
1207 len = (natoms*(t + 1))/nth - offset;
1208 put_atoms_in_box(ePBC, box, len, x + offset);
1212 void put_atoms_in_box(int ePBC,matrix box,int natoms,rvec x[])
1216 if (ePBC == epbcSCREW)
1218 gmx_fatal(FARGS,"Sorry, %s pbc is not yet supported",epbc_names[ePBC]);
1232 for(i=0; (i<natoms); i++)
1234 for(m=npbcdim-1; m>=0; m--) {
1239 x[i][d] += box[m][d];
1242 while (x[i][m] >= box[m][m])
1246 x[i][d] -= box[m][d];
1254 for(i=0; i<natoms; i++)
1256 for(d=0; d<npbcdim; d++) {
1259 x[i][d] += box[d][d];
1261 while (x[i][d] >= box[d][d])
1263 x[i][d] -= box[d][d];
1270 void put_atoms_in_triclinic_unitcell(int ecenter,matrix box,
1271 int natoms,rvec x[])
1273 rvec box_center,shift_center;
1274 real shm01,shm02,shm12,shift;
1277 calc_box_center(ecenter,box,box_center);
1279 /* The product of matrix shm with a coordinate gives the shift vector
1280 which is required determine the periodic cell position */
1281 shm01 = box[1][0]/box[1][1];
1282 shm02 = (box[1][1]*box[2][0] - box[2][1]*box[1][0])/(box[1][1]*box[2][2]);
1283 shm12 = box[2][1]/box[2][2];
1285 clear_rvec(shift_center);
1286 for(d=0; d<DIM; d++)
1287 rvec_inc(shift_center,box[d]);
1288 svmul(0.5,shift_center,shift_center);
1289 rvec_sub(box_center,shift_center,shift_center);
1291 shift_center[0] = shm01*shift_center[1] + shm02*shift_center[2];
1292 shift_center[1] = shm12*shift_center[2];
1293 shift_center[2] = 0;
1295 for(i=0; (i<natoms); i++)
1296 for(m=DIM-1; m>=0; m--) {
1297 shift = shift_center[m];
1299 shift += shm01*x[i][1] + shm02*x[i][2];
1300 } else if (m == 1) {
1301 shift += shm12*x[i][2];
1303 while (x[i][m]-shift < 0)
1305 x[i][d] += box[m][d];
1306 while (x[i][m]-shift >= box[m][m])
1308 x[i][d] -= box[m][d];
1313 put_atoms_in_compact_unitcell(int ePBC,int ecenter,matrix box,
1314 int natoms,rvec x[])
1320 set_pbc(&pbc,ePBC,box);
1321 calc_box_center(ecenter,box,box_center);
1322 for(i=0; i<natoms; i++) {
1323 pbc_dx(&pbc,x[i],box_center,dx);
1324 rvec_add(box_center,dx,x[i]);
1327 return pbc.bLimitDistance ?
1328 "WARNING: Could not put all atoms in the compact unitcell\n"