1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
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
34 * GROningen Mixture of Alchemy and Childrens' Stories
49 #include "gmx_fatal.h"
52 #include "gmx_omp_nthreads.h"
54 /* Skip 0 so we have more chance of detecting if we forgot to call set_pbc. */
55 enum { epbcdxRECTANGULAR=1, epbcdxTRICLINIC,
56 epbcdx2D_RECT, epbcdx2D_TRIC,
57 epbcdx1D_RECT, epbcdx1D_TRIC,
58 epbcdxSCREW_RECT, epbcdxSCREW_TRIC,
59 epbcdxNOPBC, epbcdxUNSUPPORTED };
61 /* Margin factor for error message and correction if the box is too skewed */
62 #define BOX_MARGIN 1.0010
63 #define BOX_MARGIN_CORRECT 1.0005
65 int ePBC2npbcdim(int ePBC)
70 case epbcXYZ: npbcdim = 3; break;
71 case epbcXY: npbcdim = 2; break;
72 case epbcSCREW: npbcdim = 3; break;
73 case epbcNONE: npbcdim = 0; break;
74 default: gmx_fatal(FARGS,"Unknown ePBC=%d in ePBC2npbcdim",ePBC);
80 int inputrec2nboundeddim(t_inputrec *ir)
82 if (ir->nwall == 2 && ir->ePBC == epbcXY)
88 return ePBC2npbcdim(ir->ePBC);
92 void dump_pbc(FILE *fp,t_pbc *pbc)
96 fprintf(fp,"ePBCDX = %d\n",pbc->ePBCDX);
97 pr_rvecs(fp,0,"box",pbc->box,DIM);
98 pr_rvecs(fp,0,"fbox_diag",&pbc->fbox_diag,1);
99 pr_rvecs(fp,0,"hbox_diag",&pbc->hbox_diag,1);
100 pr_rvecs(fp,0,"mhbox_diag",&pbc->mhbox_diag,1);
101 rvec_add(pbc->hbox_diag,pbc->mhbox_diag,sum_box);
102 pr_rvecs(fp,0,"sum of the above two",&sum_box,1);
103 fprintf(fp,"max_cutoff2 = %g\n",pbc->max_cutoff2);
104 fprintf(fp,"bLimitDistance = %s\n",EBOOL(pbc->bLimitDistance));
105 fprintf(fp,"limit_distance2 = %g\n",pbc->limit_distance2);
106 fprintf(fp,"ntric_vec = %d\n",pbc->ntric_vec);
107 if (pbc->ntric_vec > 0) {
108 pr_ivecs(fp,0,"tric_shift",pbc->tric_shift,pbc->ntric_vec,FALSE);
109 pr_rvecs(fp,0,"tric_vec",pbc->tric_vec,pbc->ntric_vec);
113 const char *check_box(int ePBC,matrix box)
118 ePBC = guess_ePBC(box);
120 if (ePBC == epbcNONE)
123 if ((box[XX][YY] != 0) || (box[XX][ZZ] != 0) || (box[YY][ZZ] != 0)) {
124 ptr = "Only triclinic boxes with the first vector parallel to the x-axis and the second vector in the xy-plane are supported.";
125 } else if (ePBC == epbcSCREW && (box[YY][XX] != 0 || box[ZZ][XX] != 0)) {
126 ptr = "The unit cell can not have off-diagonal x-components with screw pbc";
127 } else if (fabs(box[YY][XX]) > BOX_MARGIN*0.5*box[XX][XX] ||
129 (fabs(box[ZZ][XX]) > BOX_MARGIN*0.5*box[XX][XX] ||
130 fabs(box[ZZ][YY]) > BOX_MARGIN*0.5*box[YY][YY]))) {
131 ptr = "Triclinic box is too skewed.";
139 real max_cutoff2(int ePBC,matrix box)
143 /* Physical limitation of the cut-off
144 * by half the length of the shortest box vector.
146 min_hv2 = min(0.25*norm2(box[XX]),0.25*norm2(box[YY]));
148 min_hv2 = min(min_hv2,0.25*norm2(box[ZZ]));
150 /* Limitation to the smallest diagonal element due to optimizations:
151 * checking only linear combinations of single box-vectors (2 in x)
152 * in the grid search and pbc_dx is a lot faster
153 * than checking all possible combinations.
155 if (ePBC == epbcXY) {
156 min_ss = min(box[XX][XX],box[YY][YY]);
158 min_ss = min(box[XX][XX],min(box[YY][YY]-fabs(box[ZZ][YY]),box[ZZ][ZZ]));
161 return min(min_hv2,min_ss*min_ss);
164 /* this one is mostly harmless... */
165 static gmx_bool bWarnedGuess=FALSE;
167 int guess_ePBC(matrix box)
171 if (box[XX][XX]>0 && box[YY][YY]>0 && box[ZZ][ZZ]>0) {
173 } else if (box[XX][XX]>0 && box[YY][YY]>0 && box[ZZ][ZZ]==0) {
175 } else if (box[XX][XX]==0 && box[YY][YY]==0 && box[ZZ][ZZ]==0) {
179 fprintf(stderr,"WARNING: Unsupported box diagonal %f %f %f, "
180 "will not use periodic boundary conditions\n\n",
181 box[XX][XX],box[YY][YY],box[ZZ][ZZ]);
188 fprintf(debug,"Guessed pbc = %s from the box matrix\n",epbc_names[ePBC]);
193 static int correct_box_elem(FILE *fplog,int step,tensor box,int v,int d)
195 int shift,maxshift=10;
199 /* correct elem d of vector v with vector d */
200 while (box[v][d] > BOX_MARGIN_CORRECT*0.5*box[d][d]) {
202 fprintf(fplog,"Step %d: correcting invalid box:\n",step);
203 pr_rvecs(fplog,0,"old box",box,DIM);
205 rvec_dec(box[v],box[d]);
208 pr_rvecs(fplog,0,"new box",box,DIM);
210 if (shift <= -maxshift)
212 "Box was shifted at least %d times. Please see log-file.",
215 while (box[v][d] < -BOX_MARGIN_CORRECT*0.5*box[d][d]) {
217 fprintf(fplog,"Step %d: correcting invalid box:\n",step);
218 pr_rvecs(fplog,0,"old box",box,DIM);
220 rvec_inc(box[v],box[d]);
223 pr_rvecs(fplog,0,"new box",box,DIM);
225 if (shift >= maxshift)
227 "Box was shifted at least %d times. Please see log-file.",
234 gmx_bool correct_box(FILE *fplog,int step,tensor box,t_graph *graph)
239 /* check if the box still obeys the restrictions, if not, correct it */
240 zy = correct_box_elem(fplog,step,box,ZZ,YY);
241 zx = correct_box_elem(fplog,step,box,ZZ,XX);
242 yx = correct_box_elem(fplog,step,box,YY,XX);
244 bCorrected = (zy || zx || yx);
246 if (bCorrected && graph) {
247 /* correct the graph */
248 for(i=graph->at_start; i<graph->at_end; i++) {
249 graph->ishift[i][YY] -= graph->ishift[i][ZZ]*zy;
250 graph->ishift[i][XX] -= graph->ishift[i][ZZ]*zx;
251 graph->ishift[i][XX] -= graph->ishift[i][YY]*yx;
258 int ndof_com(t_inputrec *ir)
268 n = (ir->nwall == 0 ? 3 : 2);
274 gmx_incons("Unknown pbc in calc_nrdf");
280 static void low_set_pbc(t_pbc *pbc,int ePBC,ivec *dd_nc,matrix box)
282 int order[5]={0,-1,1,-2,2};
283 int ii,jj,kk,i,j,k,d,dd,jc,kc,npbcdim,shift;
285 real d2old,d2new,d2new_c;
290 pbc->ndim_ePBC = ePBC2npbcdim(ePBC);
292 copy_mat(box,pbc->box);
293 pbc->bLimitDistance = FALSE;
294 pbc->max_cutoff2 = 0;
297 for(i=0; (i<DIM); i++) {
298 pbc->fbox_diag[i] = box[i][i];
299 pbc->hbox_diag[i] = pbc->fbox_diag[i]*0.5;
300 pbc->mhbox_diag[i] = -pbc->hbox_diag[i];
303 ptr = check_box(ePBC,box);
304 if (ePBC == epbcNONE) {
305 pbc->ePBCDX = epbcdxNOPBC;
307 fprintf(stderr, "Warning: %s\n",ptr);
308 pr_rvecs(stderr,0," Box",box,DIM);
309 fprintf(stderr, " Can not fix pbc.\n");
310 pbc->ePBCDX = epbcdxUNSUPPORTED;
311 pbc->bLimitDistance = TRUE;
312 pbc->limit_distance2 = 0;
314 if (ePBC == epbcSCREW && dd_nc) {
315 /* This combinated should never appear here */
316 gmx_incons("low_set_pbc called with screw pbc and dd_nc != NULL");
320 for(i=0; i<DIM; i++) {
321 if ((dd_nc && (*dd_nc)[i] > 1) || (ePBC == epbcXY && i == ZZ)) {
330 /* 1D pbc is not an mdp option and it is therefore only used
331 * with single shifts.
333 pbc->ePBCDX = epbcdx1D_RECT;
337 for(i=0; i<pbc->dim; i++)
338 if (pbc->box[pbc->dim][i] != 0)
339 pbc->ePBCDX = epbcdx1D_TRIC;
342 pbc->ePBCDX = epbcdx2D_RECT;
349 if (pbc->box[i][j] != 0)
350 pbc->ePBCDX = epbcdx2D_TRIC;
353 if (ePBC != epbcSCREW) {
354 if (TRICLINIC(box)) {
355 pbc->ePBCDX = epbcdxTRICLINIC;
357 pbc->ePBCDX = epbcdxRECTANGULAR;
360 pbc->ePBCDX = (box[ZZ][YY]==0 ? epbcdxSCREW_RECT : epbcdxSCREW_TRIC);
361 if (pbc->ePBCDX == epbcdxSCREW_TRIC) {
363 "Screw pbc is not yet implemented for triclinic boxes.\n"
364 "Can not fix pbc.\n");
365 pbc->ePBCDX = epbcdxUNSUPPORTED;
370 gmx_fatal(FARGS,"Incorrect number of pbc dimensions with DD: %d",
373 pbc->max_cutoff2 = max_cutoff2(ePBC,box);
375 if (pbc->ePBCDX == epbcdxTRICLINIC ||
376 pbc->ePBCDX == epbcdx2D_TRIC ||
377 pbc->ePBCDX == epbcdxSCREW_TRIC) {
379 pr_rvecs(debug,0,"Box",box,DIM);
380 fprintf(debug,"max cutoff %.3f\n",sqrt(pbc->max_cutoff2));
383 /* We will only use single shifts, but we will check a few
384 * more shifts to see if there is a limiting distance
385 * above which we can not be sure of the correct distance.
387 for(kk=0; kk<5; kk++) {
389 if (!bPBC[ZZ] && k != 0)
391 for(jj=0; jj<5; jj++) {
393 if (!bPBC[YY] && j != 0)
395 for(ii=0; ii<3; ii++) {
397 if (!bPBC[XX] && i != 0)
399 /* A shift is only useful when it is trilinic */
400 if (j != 0 || k != 0) {
403 for(d=0; d<DIM; d++) {
404 trial[d] = i*box[XX][d] + j*box[YY][d] + k*box[ZZ][d];
405 /* Choose the vector within the brick around 0,0,0 that
406 * will become the shortest due to shift try.
413 pos[d] = min( pbc->hbox_diag[d],-trial[d]);
415 pos[d] = max(-pbc->hbox_diag[d],-trial[d]);
417 d2old += sqr(pos[d]);
418 d2new += sqr(pos[d] + trial[d]);
420 if (BOX_MARGIN*d2new < d2old) {
421 if (j < -1 || j > 1 || k < -1 || k > 1) {
422 /* Check if there is a single shift vector
423 * that decreases this distance even more.
433 d2new_c += sqr(pos[d] + trial[d]
434 - jc*box[YY][d] - kc*box[ZZ][d]);
435 if (d2new_c > BOX_MARGIN*d2new) {
436 /* Reject this shift vector, as there is no a priori limit
437 * to the number of shifts that decrease distances.
439 if (!pbc->bLimitDistance || d2new < pbc->limit_distance2)
440 pbc->limit_distance2 = d2new;
441 pbc->bLimitDistance = TRUE;
444 /* Check if shifts with one box vector less do better */
446 for(dd=0; dd<DIM; dd++) {
447 shift = (dd==0 ? i : (dd==1 ? j : k));
451 d2new_c += sqr(pos[d] + trial[d] - shift*box[dd][d]);
452 if (d2new_c <= BOX_MARGIN*d2new)
457 /* Accept this shift vector. */
458 if (pbc->ntric_vec >= MAX_NTRICVEC) {
459 fprintf(stderr,"\nWARNING: Found more than %d triclinic correction vectors, ignoring some.\n"
460 " There is probably something wrong with your box.\n",MAX_NTRICVEC);
461 pr_rvecs(stderr,0," Box",box,DIM);
463 copy_rvec(trial,pbc->tric_vec[pbc->ntric_vec]);
464 pbc->tric_shift[pbc->ntric_vec][XX] = i;
465 pbc->tric_shift[pbc->ntric_vec][YY] = j;
466 pbc->tric_shift[pbc->ntric_vec][ZZ] = k;
472 fprintf(debug," tricvec %2d = %2d %2d %2d %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
473 pbc->ntric_vec,i,j,k,
474 sqrt(d2old),sqrt(d2new),
475 trial[XX],trial[YY],trial[ZZ],
476 pos[XX],pos[YY],pos[ZZ]);
487 void set_pbc(t_pbc *pbc,int ePBC,matrix box)
490 ePBC = guess_ePBC(box);
492 low_set_pbc(pbc,ePBC,NULL,box);
495 t_pbc *set_pbc_dd(t_pbc *pbc,int ePBC,
496 gmx_domdec_t *dd,gmx_bool bSingleDir,matrix box)
504 if (ePBC == epbcSCREW && dd->nc[XX] > 1) {
505 /* The rotation has been taken care of during coordinate communication */
509 for(i=0; i<DIM; i++) {
510 if (dd->nc[i] <= (bSingleDir ? 1 : 2)) {
512 if (!(ePBC == epbcXY && i == ZZ))
521 low_set_pbc(pbc,ePBC,npbcdim<DIM ? &nc2 : NULL,box);
523 return (npbcdim > 0 ? pbc : NULL);
526 void pbc_dx(const t_pbc *pbc,const rvec x1, const rvec x2, rvec dx)
535 switch (pbc->ePBCDX) {
536 case epbcdxRECTANGULAR:
537 for(i=0; i<DIM; i++) {
538 while (dx[i] > pbc->hbox_diag[i]) {
539 dx[i] -= pbc->fbox_diag[i];
541 while (dx[i] <= pbc->mhbox_diag[i]) {
542 dx[i] += pbc->fbox_diag[i];
546 case epbcdxTRICLINIC:
547 for(i=DIM-1; i>=0; i--) {
548 while (dx[i] > pbc->hbox_diag[i]) {
550 dx[j] -= pbc->box[i][j];
552 while (dx[i] <= pbc->mhbox_diag[i]) {
554 dx[j] += pbc->box[i][j];
557 /* dx is the distance in a rectangular box */
559 if (d2min > pbc->max_cutoff2) {
560 copy_rvec(dx,dx_start);
562 /* Now try all possible shifts, when the distance is within max_cutoff
563 * it must be the shortest possible distance.
566 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
567 rvec_add(dx_start,pbc->tric_vec[i],trial);
568 d2trial = norm2(trial);
569 if (d2trial < d2min) {
578 for(i=0; i<DIM; i++) {
580 while (dx[i] > pbc->hbox_diag[i]) {
581 dx[i] -= pbc->fbox_diag[i];
583 while (dx[i] <= pbc->mhbox_diag[i]) {
584 dx[i] += pbc->fbox_diag[i];
591 for(i=DIM-1; i>=0; i--) {
593 while (dx[i] > pbc->hbox_diag[i]) {
595 dx[j] -= pbc->box[i][j];
597 while (dx[i] <= pbc->mhbox_diag[i]) {
599 dx[j] += pbc->box[i][j];
601 d2min += dx[i]*dx[i];
604 if (d2min > pbc->max_cutoff2) {
605 copy_rvec(dx,dx_start);
607 /* Now try all possible shifts, when the distance is within max_cutoff
608 * it must be the shortest possible distance.
611 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
612 rvec_add(dx_start,pbc->tric_vec[i],trial);
614 for(j=0; j<DIM; j++) {
616 d2trial += trial[j]*trial[j];
619 if (d2trial < d2min) {
627 case epbcdxSCREW_RECT:
628 /* The shift definition requires x first */
630 while (dx[XX] > pbc->hbox_diag[XX]) {
631 dx[XX] -= pbc->fbox_diag[XX];
634 while (dx[XX] <= pbc->mhbox_diag[XX]) {
635 dx[XX] += pbc->fbox_diag[YY];
639 /* Rotate around the x-axis in the middle of the box */
640 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
641 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
643 /* Normal pbc for y and z */
644 for(i=YY; i<=ZZ; i++) {
645 while (dx[i] > pbc->hbox_diag[i]) {
646 dx[i] -= pbc->fbox_diag[i];
648 while (dx[i] <= pbc->mhbox_diag[i]) {
649 dx[i] += pbc->fbox_diag[i];
654 case epbcdxUNSUPPORTED:
657 gmx_fatal(FARGS,"Internal error in pbc_dx, set_pbc has not been called");
662 int pbc_dx_aiuc(const t_pbc *pbc,const rvec x1, const rvec x2, rvec dx)
667 ivec ishift,ishift_start;
672 switch (pbc->ePBCDX) {
673 case epbcdxRECTANGULAR:
674 for(i=0; i<DIM; i++) {
675 if (dx[i] > pbc->hbox_diag[i]) {
676 dx[i] -= pbc->fbox_diag[i];
678 } else if (dx[i] <= pbc->mhbox_diag[i]) {
679 dx[i] += pbc->fbox_diag[i];
684 case epbcdxTRICLINIC:
685 /* For triclinic boxes the performance difference between
686 * if/else and two while loops is negligible.
687 * However, the while version can cause extreme delays
688 * before a simulation crashes due to large forces which
689 * can cause unlimited displacements.
690 * Also allowing multiple shifts would index fshift beyond bounds.
692 for(i=DIM-1; i>=1; i--) {
693 if (dx[i] > pbc->hbox_diag[i]) {
695 dx[j] -= pbc->box[i][j];
697 } else if (dx[i] <= pbc->mhbox_diag[i]) {
699 dx[j] += pbc->box[i][j];
703 /* Allow 2 shifts in x */
704 if (dx[XX] > pbc->hbox_diag[XX]) {
705 dx[XX] -= pbc->fbox_diag[XX];
707 if (dx[XX] > pbc->hbox_diag[XX]) {
708 dx[XX] -= pbc->fbox_diag[XX];
711 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
712 dx[XX] += pbc->fbox_diag[XX];
714 if (dx[XX] <= pbc->mhbox_diag[XX]) {
715 dx[XX] += pbc->fbox_diag[XX];
719 /* dx is the distance in a rectangular box */
721 if (d2min > pbc->max_cutoff2) {
722 copy_rvec(dx,dx_start);
723 copy_ivec(ishift,ishift_start);
725 /* Now try all possible shifts, when the distance is within max_cutoff
726 * it must be the shortest possible distance.
729 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
730 rvec_add(dx_start,pbc->tric_vec[i],trial);
731 d2trial = norm2(trial);
732 if (d2trial < d2min) {
734 ivec_add(ishift_start,pbc->tric_shift[i],ishift);
742 for(i=0; i<DIM; i++) {
744 if (dx[i] > pbc->hbox_diag[i]) {
745 dx[i] -= pbc->fbox_diag[i];
747 } else if (dx[i] <= pbc->mhbox_diag[i]) {
748 dx[i] += pbc->fbox_diag[i];
756 for(i=DIM-1; i>=1; i--) {
758 if (dx[i] > pbc->hbox_diag[i]) {
760 dx[j] -= pbc->box[i][j];
762 } else if (dx[i] <= pbc->mhbox_diag[i]) {
764 dx[j] += pbc->box[i][j];
767 d2min += dx[i]*dx[i];
770 if (pbc->dim != XX) {
771 /* Allow 2 shifts in x */
772 if (dx[XX] > pbc->hbox_diag[XX]) {
773 dx[XX] -= pbc->fbox_diag[XX];
775 if (dx[XX] > pbc->hbox_diag[XX]) {
776 dx[XX] -= pbc->fbox_diag[XX];
779 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
780 dx[XX] += pbc->fbox_diag[XX];
782 if (dx[XX] <= pbc->mhbox_diag[XX]) {
783 dx[XX] += pbc->fbox_diag[XX];
787 d2min += dx[XX]*dx[XX];
789 if (d2min > pbc->max_cutoff2) {
790 copy_rvec(dx,dx_start);
791 copy_ivec(ishift,ishift_start);
792 /* Now try all possible shifts, when the distance is within max_cutoff
793 * it must be the shortest possible distance.
796 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
797 rvec_add(dx_start,pbc->tric_vec[i],trial);
799 for(j=0; j<DIM; j++) {
801 d2trial += trial[j]*trial[j];
804 if (d2trial < d2min) {
806 ivec_add(ishift_start,pbc->tric_shift[i],ishift);
815 if (dx[i] > pbc->hbox_diag[i]) {
816 dx[i] -= pbc->fbox_diag[i];
818 } else if (dx[i] <= pbc->mhbox_diag[i]) {
819 dx[i] += pbc->fbox_diag[i];
825 if (dx[i] > pbc->hbox_diag[i]) {
826 rvec_dec(dx,pbc->box[i]);
828 } else if (dx[i] <= pbc->mhbox_diag[i]) {
829 rvec_inc(dx,pbc->box[i]);
833 case epbcdxSCREW_RECT:
834 /* The shift definition requires x first */
835 if (dx[XX] > pbc->hbox_diag[XX]) {
836 dx[XX] -= pbc->fbox_diag[XX];
838 } else if (dx[XX] <= pbc->mhbox_diag[XX]) {
839 dx[XX] += pbc->fbox_diag[XX];
842 if (ishift[XX] == 1 || ishift[XX] == -1) {
843 /* Rotate around the x-axis in the middle of the box */
844 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
845 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
847 /* Normal pbc for y and z */
848 for(i=YY; i<=ZZ; i++) {
849 if (dx[i] > pbc->hbox_diag[i]) {
850 dx[i] -= pbc->fbox_diag[i];
852 } else if (dx[i] <= pbc->mhbox_diag[i]) {
853 dx[i] += pbc->fbox_diag[i];
859 case epbcdxUNSUPPORTED:
862 gmx_fatal(FARGS,"Internal error in pbc_dx_aiuc, set_pbc_dd or set_pbc has not been called");
866 is = IVEC2IS(ishift);
869 range_check_mesg(is,0,SHIFTS,"PBC shift vector index range check.");
875 void pbc_dx_d(const t_pbc *pbc,const dvec x1, const dvec x2, dvec dx)
879 double d2min,d2trial;
884 switch (pbc->ePBCDX) {
885 case epbcdxRECTANGULAR:
887 for(i=0; i<DIM; i++) {
889 while (dx[i] > pbc->hbox_diag[i]) {
890 dx[i] -= pbc->fbox_diag[i];
892 while (dx[i] <= pbc->mhbox_diag[i]) {
893 dx[i] += pbc->fbox_diag[i];
898 case epbcdxTRICLINIC:
901 for(i=DIM-1; i>=0; i--) {
903 while (dx[i] > pbc->hbox_diag[i]) {
905 dx[j] -= pbc->box[i][j];
907 while (dx[i] <= pbc->mhbox_diag[i]) {
909 dx[j] += pbc->box[i][j];
911 d2min += dx[i]*dx[i];
914 if (d2min > pbc->max_cutoff2) {
915 copy_dvec(dx,dx_start);
916 /* Now try all possible shifts, when the distance is within max_cutoff
917 * it must be the shortest possible distance.
920 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec)) {
921 for(j=0; j<DIM; j++) {
922 trial[j] = dx_start[j] + pbc->tric_vec[i][j];
925 for(j=0; j<DIM; j++) {
927 d2trial += trial[j]*trial[j];
930 if (d2trial < d2min) {
938 case epbcdxSCREW_RECT:
939 /* The shift definition requires x first */
941 while (dx[XX] > pbc->hbox_diag[XX]) {
942 dx[XX] -= pbc->fbox_diag[XX];
945 while (dx[XX] <= pbc->mhbox_diag[XX]) {
946 dx[XX] += pbc->fbox_diag[YY];
950 /* Rotate around the x-axis in the middle of the box */
951 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
952 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
954 /* Normal pbc for y and z */
955 for(i=YY; i<=ZZ; i++) {
956 while (dx[i] > pbc->hbox_diag[i]) {
957 dx[i] -= pbc->fbox_diag[i];
959 while (dx[i] <= pbc->mhbox_diag[i]) {
960 dx[i] += pbc->fbox_diag[i];
965 case epbcdxUNSUPPORTED:
968 gmx_fatal(FARGS,"Internal error in pbc_dx, set_pbc has not been called");
973 gmx_bool image_rect(ivec xi,ivec xj,ivec box_size,real rlong2,int *shift,real *r2)
981 for(m=0; (m<DIM); m++) {
1005 gmx_bool image_cylindric(ivec xi,ivec xj,ivec box_size,real rlong2,
1006 int *shift,real *r2)
1014 for(m=0; (m<DIM); m++) {
1041 void calc_shifts(matrix box,rvec shift_vec[])
1046 for(m = -D_BOX_Z; m <= D_BOX_Z; m++)
1047 for(l = -D_BOX_Y; l <= D_BOX_Y; l++)
1048 for(k = -D_BOX_X; k <= D_BOX_X; k++,n++) {
1049 test = XYZ2IS(k,l,m);
1051 gmx_incons("inconsistent shift numbering");
1052 for(d = 0; d < DIM; d++)
1053 shift_vec[n][d] = k*box[XX][d] + l*box[YY][d] + m*box[ZZ][d];
1057 void calc_box_center(int ecenter,matrix box,rvec box_center)
1061 clear_rvec(box_center);
1064 for(m=0; (m<DIM); m++)
1065 for(d=0; d<DIM; d++)
1066 box_center[d] += 0.5*box[m][d];
1069 for(d=0; d<DIM; d++)
1070 box_center[d] = 0.5*box[d][d];
1075 gmx_fatal(FARGS,"Unsupported value %d for ecenter",ecenter);
1079 void calc_triclinic_images(matrix box,rvec img[])
1083 /* Calculate 3 adjacent images in the xy-plane */
1084 copy_rvec(box[0],img[0]);
1085 copy_rvec(box[1],img[1]);
1087 svmul(-1,img[1],img[1]);
1088 rvec_sub(img[1],img[0],img[2]);
1090 /* Get the next 3 in the xy-plane as mirror images */
1092 svmul(-1,img[i],img[3+i]);
1094 /* Calculate the first 4 out of xy-plane images */
1095 copy_rvec(box[2],img[6]);
1097 svmul(-1,img[6],img[6]);
1099 rvec_add(img[6],img[i+1],img[7+i]);
1101 /* Mirror the last 4 from the previous in opposite rotation */
1103 svmul(-1,img[6 + (2+i) % 4],img[10+i]);
1106 void calc_compact_unitcell_vertices(int ecenter,matrix box,rvec vert[])
1108 rvec img[NTRICIMG],box_center;
1111 calc_triclinic_images(box,img);
1114 for(i=2; i<=5; i+=3) {
1122 for(j=0; j<4; j++) {
1123 for(d=0; d<DIM; d++)
1124 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1128 for(i=7; i<=13; i+=6) {
1136 for(j=0; j<4; j++) {
1137 for(d=0; d<DIM; d++)
1138 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1142 for(i=9; i<=11; i+=2) {
1153 for(j=0; j<4; j++) {
1154 for(d=0; d<DIM; d++)
1155 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1160 calc_box_center(ecenter,box,box_center);
1161 for(i=0; i<NCUCVERT; i++)
1162 for(d=0; d<DIM; d++)
1163 vert[i][d] = vert[i][d]*0.25+box_center[d];
1166 int *compact_unitcell_edges()
1168 /* this is an index in vert[] (see calc_box_vertices) */
1169 /*static int edge[NCUCEDGE*2];*/
1171 static const int hexcon[24] = { 0,9, 1,19, 2,15, 3,21,
1172 4,17, 5,11, 6,23, 7,13,
1173 8,20, 10,18, 12,16, 14,22 };
1175 gmx_bool bFirst = TRUE;
1177 snew(edge,NCUCEDGE*2);
1182 for(j=0; j<4; j++) {
1183 edge[e++] = 4*i + j;
1184 edge[e++] = 4*i + (j+1) % 4;
1186 for(i=0; i<12*2; i++)
1187 edge[e++] = hexcon[i];
1195 void put_atoms_in_box_omp(int ePBC,matrix box,int natoms,rvec x[])
1198 nth = gmx_omp_nthreads_get(emntDefault);
1200 #pragma omp parallel for num_threads(nth) schedule(static)
1201 for(t=0; t<nth; t++)
1205 offset = (natoms*t )/nth;
1206 len = (natoms*(t + 1))/nth - offset;
1207 put_atoms_in_box(ePBC, box, len, x + offset);
1211 void put_atoms_in_box(int ePBC,matrix box,int natoms,rvec x[])
1215 if (ePBC == epbcSCREW)
1217 gmx_fatal(FARGS,"Sorry, %s pbc is not yet supported",epbc_names[ePBC]);
1231 for(i=0; (i<natoms); i++)
1233 for(m=npbcdim-1; m>=0; m--) {
1238 x[i][d] += box[m][d];
1241 while (x[i][m] >= box[m][m])
1245 x[i][d] -= box[m][d];
1253 for(i=0; i<natoms; i++)
1255 for(d=0; d<npbcdim; d++) {
1258 x[i][d] += box[d][d];
1260 while (x[i][d] >= box[d][d])
1262 x[i][d] -= box[d][d];
1269 void put_atoms_in_triclinic_unitcell(int ecenter,matrix box,
1270 int natoms,rvec x[])
1272 rvec box_center,shift_center;
1273 real shm01,shm02,shm12,shift;
1276 calc_box_center(ecenter,box,box_center);
1278 /* The product of matrix shm with a coordinate gives the shift vector
1279 which is required determine the periodic cell position */
1280 shm01 = box[1][0]/box[1][1];
1281 shm02 = (box[1][1]*box[2][0] - box[2][1]*box[1][0])/(box[1][1]*box[2][2]);
1282 shm12 = box[2][1]/box[2][2];
1284 clear_rvec(shift_center);
1285 for(d=0; d<DIM; d++)
1286 rvec_inc(shift_center,box[d]);
1287 svmul(0.5,shift_center,shift_center);
1288 rvec_sub(box_center,shift_center,shift_center);
1290 shift_center[0] = shm01*shift_center[1] + shm02*shift_center[2];
1291 shift_center[1] = shm12*shift_center[2];
1292 shift_center[2] = 0;
1294 for(i=0; (i<natoms); i++)
1295 for(m=DIM-1; m>=0; m--) {
1296 shift = shift_center[m];
1298 shift += shm01*x[i][1] + shm02*x[i][2];
1299 } else if (m == 1) {
1300 shift += shm12*x[i][2];
1302 while (x[i][m]-shift < 0)
1304 x[i][d] += box[m][d];
1305 while (x[i][m]-shift >= box[m][m])
1307 x[i][d] -= box[m][d];
1312 put_atoms_in_compact_unitcell(int ePBC,int ecenter,matrix box,
1313 int natoms,rvec x[])
1319 set_pbc(&pbc,ePBC,box);
1320 calc_box_center(ecenter,box,box_center);
1321 for(i=0; i<natoms; i++) {
1322 pbc_dx(&pbc,x[i],box_center,dx);
1323 rvec_add(box_center,dx,x[i]);
1326 return pbc.bLimitDistance ?
1327 "WARNING: Could not put all atoms in the compact unitcell\n"