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"
51 #include "gmx_omp_nthreads.h"
53 /* Skip 0 so we have more chance of detecting if we forgot to call set_pbc. */
54 enum { epbcdxRECTANGULAR
=1, epbcdxTRICLINIC
,
55 epbcdx2D_RECT
, epbcdx2D_TRIC
,
56 epbcdx1D_RECT
, epbcdx1D_TRIC
,
57 epbcdxSCREW_RECT
, epbcdxSCREW_TRIC
,
58 epbcdxNOPBC
, epbcdxUNSUPPORTED
};
60 /* Margin factor for error message and correction if the box is too skewed */
61 #define BOX_MARGIN 1.0010
62 #define BOX_MARGIN_CORRECT 1.0005
64 int ePBC2npbcdim(int ePBC
)
69 case epbcXYZ
: npbcdim
= 3; break;
70 case epbcXY
: npbcdim
= 2; break;
71 case epbcSCREW
: npbcdim
= 3; break;
72 case epbcNONE
: npbcdim
= 0; break;
73 default: gmx_fatal(FARGS
,"Unknown ePBC=%d in ePBC2npbcdim",ePBC
);
79 int inputrec2nboundeddim(t_inputrec
*ir
)
81 if (ir
->nwall
== 2 && ir
->ePBC
== epbcXY
)
87 return ePBC2npbcdim(ir
->ePBC
);
91 void dump_pbc(FILE *fp
,t_pbc
*pbc
)
95 fprintf(fp
,"ePBCDX = %d\n",pbc
->ePBCDX
);
96 pr_rvecs(fp
,0,"box",pbc
->box
,DIM
);
97 pr_rvecs(fp
,0,"fbox_diag",&pbc
->fbox_diag
,1);
98 pr_rvecs(fp
,0,"hbox_diag",&pbc
->hbox_diag
,1);
99 pr_rvecs(fp
,0,"mhbox_diag",&pbc
->mhbox_diag
,1);
100 rvec_add(pbc
->hbox_diag
,pbc
->mhbox_diag
,sum_box
);
101 pr_rvecs(fp
,0,"sum of the above two",&sum_box
,1);
102 fprintf(fp
,"max_cutoff2 = %g\n",pbc
->max_cutoff2
);
103 fprintf(fp
,"bLimitDistance = %s\n",EBOOL(pbc
->bLimitDistance
));
104 fprintf(fp
,"limit_distance2 = %g\n",pbc
->limit_distance2
);
105 fprintf(fp
,"ntric_vec = %d\n",pbc
->ntric_vec
);
106 if (pbc
->ntric_vec
> 0) {
107 pr_ivecs(fp
,0,"tric_shift",pbc
->tric_shift
,pbc
->ntric_vec
,FALSE
);
108 pr_rvecs(fp
,0,"tric_vec",pbc
->tric_vec
,pbc
->ntric_vec
);
112 const char *check_box(int ePBC
,matrix box
)
117 ePBC
= guess_ePBC(box
);
119 if (ePBC
== epbcNONE
)
122 if ((box
[XX
][YY
] != 0) || (box
[XX
][ZZ
] != 0) || (box
[YY
][ZZ
] != 0)) {
123 ptr
= "Only triclinic boxes with the first vector parallel to the x-axis and the second vector in the xy-plane are supported.";
124 } else if (ePBC
== epbcSCREW
&& (box
[YY
][XX
] != 0 || box
[ZZ
][XX
] != 0)) {
125 ptr
= "The unit cell can not have off-diagonal x-components with screw pbc";
126 } else if (fabs(box
[YY
][XX
]) > BOX_MARGIN
*0.5*box
[XX
][XX
] ||
128 (fabs(box
[ZZ
][XX
]) > BOX_MARGIN
*0.5*box
[XX
][XX
] ||
129 fabs(box
[ZZ
][YY
]) > BOX_MARGIN
*0.5*box
[YY
][YY
]))) {
130 ptr
= "Triclinic box is too skewed.";
138 real
max_cutoff2(int ePBC
,matrix box
)
142 /* Physical limitation of the cut-off
143 * by half the length of the shortest box vector.
145 min_hv2
= min(0.25*norm2(box
[XX
]),0.25*norm2(box
[YY
]));
147 min_hv2
= min(min_hv2
,0.25*norm2(box
[ZZ
]));
149 /* Limitation to the smallest diagonal element due to optimizations:
150 * checking only linear combinations of single box-vectors (2 in x)
151 * in the grid search and pbc_dx is a lot faster
152 * than checking all possible combinations.
154 if (ePBC
== epbcXY
) {
155 min_ss
= min(box
[XX
][XX
],box
[YY
][YY
]);
157 min_ss
= min(box
[XX
][XX
],min(box
[YY
][YY
]-fabs(box
[ZZ
][YY
]),box
[ZZ
][ZZ
]));
160 return min(min_hv2
,min_ss
*min_ss
);
163 /* this one is mostly harmless... */
164 static gmx_bool bWarnedGuess
=FALSE
;
166 int guess_ePBC(matrix box
)
170 if (box
[XX
][XX
]>0 && box
[YY
][YY
]>0 && box
[ZZ
][ZZ
]>0) {
172 } else 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) {
178 fprintf(stderr
,"WARNING: Unsupported box diagonal %f %f %f, "
179 "will not use periodic boundary conditions\n\n",
180 box
[XX
][XX
],box
[YY
][YY
],box
[ZZ
][ZZ
]);
187 fprintf(debug
,"Guessed pbc = %s from the box matrix\n",epbc_names
[ePBC
]);
192 static int correct_box_elem(FILE *fplog
,int step
,tensor box
,int v
,int d
)
194 int shift
,maxshift
=10;
198 /* correct elem d of vector v with vector d */
199 while (box
[v
][d
] > BOX_MARGIN_CORRECT
*0.5*box
[d
][d
]) {
201 fprintf(fplog
,"Step %d: correcting invalid box:\n",step
);
202 pr_rvecs(fplog
,0,"old box",box
,DIM
);
204 rvec_dec(box
[v
],box
[d
]);
207 pr_rvecs(fplog
,0,"new box",box
,DIM
);
209 if (shift
<= -maxshift
)
211 "Box was shifted at least %d times. Please see log-file.",
214 while (box
[v
][d
] < -BOX_MARGIN_CORRECT
*0.5*box
[d
][d
]) {
216 fprintf(fplog
,"Step %d: correcting invalid box:\n",step
);
217 pr_rvecs(fplog
,0,"old box",box
,DIM
);
219 rvec_inc(box
[v
],box
[d
]);
222 pr_rvecs(fplog
,0,"new box",box
,DIM
);
224 if (shift
>= maxshift
)
226 "Box was shifted at least %d times. Please see log-file.",
233 gmx_bool
correct_box(FILE *fplog
,int step
,tensor box
,t_graph
*graph
)
238 /* check if the box still obeys the restrictions, if not, correct it */
239 zy
= correct_box_elem(fplog
,step
,box
,ZZ
,YY
);
240 zx
= correct_box_elem(fplog
,step
,box
,ZZ
,XX
);
241 yx
= correct_box_elem(fplog
,step
,box
,YY
,XX
);
243 bCorrected
= (zy
|| zx
|| yx
);
245 if (bCorrected
&& graph
) {
246 /* correct the graph */
247 for(i
=graph
->at_start
; i
<graph
->at_end
; i
++) {
248 graph
->ishift
[i
][YY
] -= graph
->ishift
[i
][ZZ
]*zy
;
249 graph
->ishift
[i
][XX
] -= graph
->ishift
[i
][ZZ
]*zx
;
250 graph
->ishift
[i
][XX
] -= graph
->ishift
[i
][YY
]*yx
;
257 int ndof_com(t_inputrec
*ir
)
267 n
= (ir
->nwall
== 0 ? 3 : 2);
273 gmx_incons("Unknown pbc in calc_nrdf");
279 static void low_set_pbc(t_pbc
*pbc
,int ePBC
,ivec
*dd_nc
,matrix box
)
281 int order
[5]={0,-1,1,-2,2};
282 int ii
,jj
,kk
,i
,j
,k
,d
,dd
,jc
,kc
,npbcdim
,shift
;
284 real d2old
,d2new
,d2new_c
;
289 pbc
->ndim_ePBC
= ePBC2npbcdim(ePBC
);
291 copy_mat(box
,pbc
->box
);
292 pbc
->bLimitDistance
= FALSE
;
293 pbc
->max_cutoff2
= 0;
296 for(i
=0; (i
<DIM
); i
++) {
297 pbc
->fbox_diag
[i
] = box
[i
][i
];
298 pbc
->hbox_diag
[i
] = pbc
->fbox_diag
[i
]*0.5;
299 pbc
->mhbox_diag
[i
] = -pbc
->hbox_diag
[i
];
302 ptr
= check_box(ePBC
,box
);
303 if (ePBC
== epbcNONE
) {
304 pbc
->ePBCDX
= epbcdxNOPBC
;
306 fprintf(stderr
, "Warning: %s\n",ptr
);
307 pr_rvecs(stderr
,0," Box",box
,DIM
);
308 fprintf(stderr
, " Can not fix pbc.\n");
309 pbc
->ePBCDX
= epbcdxUNSUPPORTED
;
310 pbc
->bLimitDistance
= TRUE
;
311 pbc
->limit_distance2
= 0;
313 if (ePBC
== epbcSCREW
&& dd_nc
) {
314 /* This combinated should never appear here */
315 gmx_incons("low_set_pbc called with screw pbc and dd_nc != NULL");
319 for(i
=0; i
<DIM
; i
++) {
320 if ((dd_nc
&& (*dd_nc
)[i
] > 1) || (ePBC
== epbcXY
&& i
== ZZ
)) {
329 /* 1D pbc is not an mdp option and it is therefore only used
330 * with single shifts.
332 pbc
->ePBCDX
= epbcdx1D_RECT
;
336 for(i
=0; i
<pbc
->dim
; i
++)
337 if (pbc
->box
[pbc
->dim
][i
] != 0)
338 pbc
->ePBCDX
= epbcdx1D_TRIC
;
341 pbc
->ePBCDX
= epbcdx2D_RECT
;
348 if (pbc
->box
[i
][j
] != 0)
349 pbc
->ePBCDX
= epbcdx2D_TRIC
;
352 if (ePBC
!= epbcSCREW
) {
353 if (TRICLINIC(box
)) {
354 pbc
->ePBCDX
= epbcdxTRICLINIC
;
356 pbc
->ePBCDX
= epbcdxRECTANGULAR
;
359 pbc
->ePBCDX
= (box
[ZZ
][YY
]==0 ? epbcdxSCREW_RECT
: epbcdxSCREW_TRIC
);
360 if (pbc
->ePBCDX
== epbcdxSCREW_TRIC
) {
362 "Screw pbc is not yet implemented for triclinic boxes.\n"
363 "Can not fix pbc.\n");
364 pbc
->ePBCDX
= epbcdxUNSUPPORTED
;
369 gmx_fatal(FARGS
,"Incorrect number of pbc dimensions with DD: %d",
372 pbc
->max_cutoff2
= max_cutoff2(ePBC
,box
);
374 if (pbc
->ePBCDX
== epbcdxTRICLINIC
||
375 pbc
->ePBCDX
== epbcdx2D_TRIC
||
376 pbc
->ePBCDX
== epbcdxSCREW_TRIC
) {
378 pr_rvecs(debug
,0,"Box",box
,DIM
);
379 fprintf(debug
,"max cutoff %.3f\n",sqrt(pbc
->max_cutoff2
));
382 /* We will only use single shifts, but we will check a few
383 * more shifts to see if there is a limiting distance
384 * above which we can not be sure of the correct distance.
386 for(kk
=0; kk
<5; kk
++) {
388 if (!bPBC
[ZZ
] && k
!= 0)
390 for(jj
=0; jj
<5; jj
++) {
392 if (!bPBC
[YY
] && j
!= 0)
394 for(ii
=0; ii
<3; ii
++) {
396 if (!bPBC
[XX
] && i
!= 0)
398 /* A shift is only useful when it is trilinic */
399 if (j
!= 0 || k
!= 0) {
402 for(d
=0; d
<DIM
; d
++) {
403 trial
[d
] = i
*box
[XX
][d
] + j
*box
[YY
][d
] + k
*box
[ZZ
][d
];
404 /* Choose the vector within the brick around 0,0,0 that
405 * will become the shortest due to shift try.
412 pos
[d
] = min( pbc
->hbox_diag
[d
],-trial
[d
]);
414 pos
[d
] = max(-pbc
->hbox_diag
[d
],-trial
[d
]);
416 d2old
+= sqr(pos
[d
]);
417 d2new
+= sqr(pos
[d
] + trial
[d
]);
419 if (BOX_MARGIN
*d2new
< d2old
) {
420 if (j
< -1 || j
> 1 || k
< -1 || k
> 1) {
421 /* Check if there is a single shift vector
422 * that decreases this distance even more.
432 d2new_c
+= sqr(pos
[d
] + trial
[d
]
433 - jc
*box
[YY
][d
] - kc
*box
[ZZ
][d
]);
434 if (d2new_c
> BOX_MARGIN
*d2new
) {
435 /* Reject this shift vector, as there is no a priori limit
436 * to the number of shifts that decrease distances.
438 if (!pbc
->bLimitDistance
|| d2new
< pbc
->limit_distance2
)
439 pbc
->limit_distance2
= d2new
;
440 pbc
->bLimitDistance
= TRUE
;
443 /* Check if shifts with one box vector less do better */
445 for(dd
=0; dd
<DIM
; dd
++) {
446 shift
= (dd
==0 ? i
: (dd
==1 ? j
: k
));
450 d2new_c
+= sqr(pos
[d
] + trial
[d
] - shift
*box
[dd
][d
]);
451 if (d2new_c
<= BOX_MARGIN
*d2new
)
456 /* Accept this shift vector. */
457 if (pbc
->ntric_vec
>= MAX_NTRICVEC
) {
458 fprintf(stderr
,"\nWARNING: Found more than %d triclinic correction vectors, ignoring some.\n"
459 " There is probably something wrong with your box.\n",MAX_NTRICVEC
);
460 pr_rvecs(stderr
,0," Box",box
,DIM
);
462 copy_rvec(trial
,pbc
->tric_vec
[pbc
->ntric_vec
]);
463 pbc
->tric_shift
[pbc
->ntric_vec
][XX
] = i
;
464 pbc
->tric_shift
[pbc
->ntric_vec
][YY
] = j
;
465 pbc
->tric_shift
[pbc
->ntric_vec
][ZZ
] = k
;
471 fprintf(debug
," tricvec %2d = %2d %2d %2d %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
472 pbc
->ntric_vec
,i
,j
,k
,
473 sqrt(d2old
),sqrt(d2new
),
474 trial
[XX
],trial
[YY
],trial
[ZZ
],
475 pos
[XX
],pos
[YY
],pos
[ZZ
]);
486 void set_pbc(t_pbc
*pbc
,int ePBC
,matrix box
)
489 ePBC
= guess_ePBC(box
);
491 low_set_pbc(pbc
,ePBC
,NULL
,box
);
494 t_pbc
*set_pbc_dd(t_pbc
*pbc
,int ePBC
,
495 gmx_domdec_t
*dd
,gmx_bool bSingleDir
,matrix box
)
503 if (ePBC
== epbcSCREW
&& dd
->nc
[XX
] > 1) {
504 /* The rotation has been taken care of during coordinate communication */
508 for(i
=0; i
<DIM
; i
++) {
509 if (dd
->nc
[i
] <= (bSingleDir
? 1 : 2)) {
511 if (!(ePBC
== epbcXY
&& i
== ZZ
))
520 low_set_pbc(pbc
,ePBC
,npbcdim
<DIM
? &nc2
: NULL
,box
);
522 return (npbcdim
> 0 ? pbc
: NULL
);
525 void pbc_dx(const t_pbc
*pbc
,const rvec x1
, const rvec x2
, rvec dx
)
534 switch (pbc
->ePBCDX
) {
535 case epbcdxRECTANGULAR
:
536 for(i
=0; i
<DIM
; i
++) {
537 while (dx
[i
] > pbc
->hbox_diag
[i
]) {
538 dx
[i
] -= pbc
->fbox_diag
[i
];
540 while (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
541 dx
[i
] += pbc
->fbox_diag
[i
];
545 case epbcdxTRICLINIC
:
546 for(i
=DIM
-1; i
>=0; i
--) {
547 while (dx
[i
] > pbc
->hbox_diag
[i
]) {
549 dx
[j
] -= pbc
->box
[i
][j
];
551 while (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
553 dx
[j
] += pbc
->box
[i
][j
];
556 /* dx is the distance in a rectangular box */
558 if (d2min
> pbc
->max_cutoff2
) {
559 copy_rvec(dx
,dx_start
);
561 /* Now try all possible shifts, when the distance is within max_cutoff
562 * it must be the shortest possible distance.
565 while ((d2min
> pbc
->max_cutoff2
) && (i
< pbc
->ntric_vec
)) {
566 rvec_add(dx_start
,pbc
->tric_vec
[i
],trial
);
567 d2trial
= norm2(trial
);
568 if (d2trial
< d2min
) {
577 for(i
=0; i
<DIM
; i
++) {
579 while (dx
[i
] > pbc
->hbox_diag
[i
]) {
580 dx
[i
] -= pbc
->fbox_diag
[i
];
582 while (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
583 dx
[i
] += pbc
->fbox_diag
[i
];
590 for(i
=DIM
-1; i
>=0; i
--) {
592 while (dx
[i
] > pbc
->hbox_diag
[i
]) {
594 dx
[j
] -= pbc
->box
[i
][j
];
596 while (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
598 dx
[j
] += pbc
->box
[i
][j
];
600 d2min
+= dx
[i
]*dx
[i
];
603 if (d2min
> pbc
->max_cutoff2
) {
604 copy_rvec(dx
,dx_start
);
606 /* Now try all possible shifts, when the distance is within max_cutoff
607 * it must be the shortest possible distance.
610 while ((d2min
> pbc
->max_cutoff2
) && (i
< pbc
->ntric_vec
)) {
611 rvec_add(dx_start
,pbc
->tric_vec
[i
],trial
);
613 for(j
=0; j
<DIM
; j
++) {
615 d2trial
+= trial
[j
]*trial
[j
];
618 if (d2trial
< d2min
) {
626 case epbcdxSCREW_RECT
:
627 /* The shift definition requires x first */
629 while (dx
[XX
] > pbc
->hbox_diag
[XX
]) {
630 dx
[XX
] -= pbc
->fbox_diag
[XX
];
633 while (dx
[XX
] <= pbc
->mhbox_diag
[XX
]) {
634 dx
[XX
] += pbc
->fbox_diag
[YY
];
638 /* Rotate around the x-axis in the middle of the box */
639 dx
[YY
] = pbc
->box
[YY
][YY
] - x1
[YY
] - x2
[YY
];
640 dx
[ZZ
] = pbc
->box
[ZZ
][ZZ
] - x1
[ZZ
] - x2
[ZZ
];
642 /* Normal pbc for y and z */
643 for(i
=YY
; i
<=ZZ
; i
++) {
644 while (dx
[i
] > pbc
->hbox_diag
[i
]) {
645 dx
[i
] -= pbc
->fbox_diag
[i
];
647 while (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
648 dx
[i
] += pbc
->fbox_diag
[i
];
653 case epbcdxUNSUPPORTED
:
656 gmx_fatal(FARGS
,"Internal error in pbc_dx, set_pbc has not been called");
661 int pbc_dx_aiuc(const t_pbc
*pbc
,const rvec x1
, const rvec x2
, rvec dx
)
666 ivec ishift
,ishift_start
;
671 switch (pbc
->ePBCDX
) {
672 case epbcdxRECTANGULAR
:
673 for(i
=0; i
<DIM
; i
++) {
674 if (dx
[i
] > pbc
->hbox_diag
[i
]) {
675 dx
[i
] -= pbc
->fbox_diag
[i
];
677 } else if (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
678 dx
[i
] += pbc
->fbox_diag
[i
];
683 case epbcdxTRICLINIC
:
684 /* For triclinic boxes the performance difference between
685 * if/else and two while loops is negligible.
686 * However, the while version can cause extreme delays
687 * before a simulation crashes due to large forces which
688 * can cause unlimited displacements.
689 * Also allowing multiple shifts would index fshift beyond bounds.
691 for(i
=DIM
-1; i
>=1; i
--) {
692 if (dx
[i
] > pbc
->hbox_diag
[i
]) {
694 dx
[j
] -= pbc
->box
[i
][j
];
696 } else if (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
698 dx
[j
] += pbc
->box
[i
][j
];
702 /* Allow 2 shifts in x */
703 if (dx
[XX
] > pbc
->hbox_diag
[XX
]) {
704 dx
[XX
] -= pbc
->fbox_diag
[XX
];
706 if (dx
[XX
] > pbc
->hbox_diag
[XX
]) {
707 dx
[XX
] -= pbc
->fbox_diag
[XX
];
710 } else if (dx
[XX
] <= pbc
->mhbox_diag
[XX
]) {
711 dx
[XX
] += pbc
->fbox_diag
[XX
];
713 if (dx
[XX
] <= pbc
->mhbox_diag
[XX
]) {
714 dx
[XX
] += pbc
->fbox_diag
[XX
];
718 /* dx is the distance in a rectangular box */
720 if (d2min
> pbc
->max_cutoff2
) {
721 copy_rvec(dx
,dx_start
);
722 copy_ivec(ishift
,ishift_start
);
724 /* Now try all possible shifts, when the distance is within max_cutoff
725 * it must be the shortest possible distance.
728 while ((d2min
> pbc
->max_cutoff2
) && (i
< pbc
->ntric_vec
)) {
729 rvec_add(dx_start
,pbc
->tric_vec
[i
],trial
);
730 d2trial
= norm2(trial
);
731 if (d2trial
< d2min
) {
733 ivec_add(ishift_start
,pbc
->tric_shift
[i
],ishift
);
741 for(i
=0; i
<DIM
; i
++) {
743 if (dx
[i
] > pbc
->hbox_diag
[i
]) {
744 dx
[i
] -= pbc
->fbox_diag
[i
];
746 } else if (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
747 dx
[i
] += pbc
->fbox_diag
[i
];
755 for(i
=DIM
-1; i
>=1; i
--) {
757 if (dx
[i
] > pbc
->hbox_diag
[i
]) {
759 dx
[j
] -= pbc
->box
[i
][j
];
761 } else if (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
763 dx
[j
] += pbc
->box
[i
][j
];
766 d2min
+= dx
[i
]*dx
[i
];
769 if (pbc
->dim
!= XX
) {
770 /* Allow 2 shifts in x */
771 if (dx
[XX
] > pbc
->hbox_diag
[XX
]) {
772 dx
[XX
] -= pbc
->fbox_diag
[XX
];
774 if (dx
[XX
] > pbc
->hbox_diag
[XX
]) {
775 dx
[XX
] -= pbc
->fbox_diag
[XX
];
778 } else if (dx
[XX
] <= pbc
->mhbox_diag
[XX
]) {
779 dx
[XX
] += pbc
->fbox_diag
[XX
];
781 if (dx
[XX
] <= pbc
->mhbox_diag
[XX
]) {
782 dx
[XX
] += pbc
->fbox_diag
[XX
];
786 d2min
+= dx
[XX
]*dx
[XX
];
788 if (d2min
> pbc
->max_cutoff2
) {
789 copy_rvec(dx
,dx_start
);
790 copy_ivec(ishift
,ishift_start
);
791 /* Now try all possible shifts, when the distance is within max_cutoff
792 * it must be the shortest possible distance.
795 while ((d2min
> pbc
->max_cutoff2
) && (i
< pbc
->ntric_vec
)) {
796 rvec_add(dx_start
,pbc
->tric_vec
[i
],trial
);
798 for(j
=0; j
<DIM
; j
++) {
800 d2trial
+= trial
[j
]*trial
[j
];
803 if (d2trial
< d2min
) {
805 ivec_add(ishift_start
,pbc
->tric_shift
[i
],ishift
);
814 if (dx
[i
] > pbc
->hbox_diag
[i
]) {
815 dx
[i
] -= pbc
->fbox_diag
[i
];
817 } else if (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
818 dx
[i
] += pbc
->fbox_diag
[i
];
824 if (dx
[i
] > pbc
->hbox_diag
[i
]) {
825 rvec_dec(dx
,pbc
->box
[i
]);
827 } else if (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
828 rvec_inc(dx
,pbc
->box
[i
]);
832 case epbcdxSCREW_RECT
:
833 /* The shift definition requires x first */
834 if (dx
[XX
] > pbc
->hbox_diag
[XX
]) {
835 dx
[XX
] -= pbc
->fbox_diag
[XX
];
837 } else if (dx
[XX
] <= pbc
->mhbox_diag
[XX
]) {
838 dx
[XX
] += pbc
->fbox_diag
[XX
];
841 if (ishift
[XX
] == 1 || ishift
[XX
] == -1) {
842 /* Rotate around the x-axis in the middle of the box */
843 dx
[YY
] = pbc
->box
[YY
][YY
] - x1
[YY
] - x2
[YY
];
844 dx
[ZZ
] = pbc
->box
[ZZ
][ZZ
] - x1
[ZZ
] - x2
[ZZ
];
846 /* Normal pbc for y and z */
847 for(i
=YY
; i
<=ZZ
; i
++) {
848 if (dx
[i
] > pbc
->hbox_diag
[i
]) {
849 dx
[i
] -= pbc
->fbox_diag
[i
];
851 } else if (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
852 dx
[i
] += pbc
->fbox_diag
[i
];
858 case epbcdxUNSUPPORTED
:
861 gmx_fatal(FARGS
,"Internal error in pbc_dx_aiuc, set_pbc_dd or set_pbc has not been called");
865 is
= IVEC2IS(ishift
);
868 range_check_mesg(is
,0,SHIFTS
,"PBC shift vector index range check.");
874 void pbc_dx_d(const t_pbc
*pbc
,const dvec x1
, const dvec x2
, dvec dx
)
878 double d2min
,d2trial
;
883 switch (pbc
->ePBCDX
) {
884 case epbcdxRECTANGULAR
:
886 for(i
=0; i
<DIM
; i
++) {
888 while (dx
[i
] > pbc
->hbox_diag
[i
]) {
889 dx
[i
] -= pbc
->fbox_diag
[i
];
891 while (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
892 dx
[i
] += pbc
->fbox_diag
[i
];
897 case epbcdxTRICLINIC
:
900 for(i
=DIM
-1; i
>=0; i
--) {
902 while (dx
[i
] > pbc
->hbox_diag
[i
]) {
904 dx
[j
] -= pbc
->box
[i
][j
];
906 while (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
908 dx
[j
] += pbc
->box
[i
][j
];
910 d2min
+= dx
[i
]*dx
[i
];
913 if (d2min
> pbc
->max_cutoff2
) {
914 copy_dvec(dx
,dx_start
);
915 /* Now try all possible shifts, when the distance is within max_cutoff
916 * it must be the shortest possible distance.
919 while ((d2min
> pbc
->max_cutoff2
) && (i
< pbc
->ntric_vec
)) {
920 for(j
=0; j
<DIM
; j
++) {
921 trial
[j
] = dx_start
[j
] + pbc
->tric_vec
[i
][j
];
924 for(j
=0; j
<DIM
; j
++) {
926 d2trial
+= trial
[j
]*trial
[j
];
929 if (d2trial
< d2min
) {
937 case epbcdxSCREW_RECT
:
938 /* The shift definition requires x first */
940 while (dx
[XX
] > pbc
->hbox_diag
[XX
]) {
941 dx
[XX
] -= pbc
->fbox_diag
[XX
];
944 while (dx
[XX
] <= pbc
->mhbox_diag
[XX
]) {
945 dx
[XX
] += pbc
->fbox_diag
[YY
];
949 /* Rotate around the x-axis in the middle of the box */
950 dx
[YY
] = pbc
->box
[YY
][YY
] - x1
[YY
] - x2
[YY
];
951 dx
[ZZ
] = pbc
->box
[ZZ
][ZZ
] - x1
[ZZ
] - x2
[ZZ
];
953 /* Normal pbc for y and z */
954 for(i
=YY
; i
<=ZZ
; i
++) {
955 while (dx
[i
] > pbc
->hbox_diag
[i
]) {
956 dx
[i
] -= pbc
->fbox_diag
[i
];
958 while (dx
[i
] <= pbc
->mhbox_diag
[i
]) {
959 dx
[i
] += pbc
->fbox_diag
[i
];
964 case epbcdxUNSUPPORTED
:
967 gmx_fatal(FARGS
,"Internal error in pbc_dx, set_pbc has not been called");
972 gmx_bool
image_rect(ivec xi
,ivec xj
,ivec box_size
,real rlong2
,int *shift
,real
*r2
)
980 for(m
=0; (m
<DIM
); m
++) {
1004 gmx_bool
image_cylindric(ivec xi
,ivec xj
,ivec box_size
,real rlong2
,
1005 int *shift
,real
*r2
)
1013 for(m
=0; (m
<DIM
); m
++) {
1040 void calc_shifts(matrix box
,rvec shift_vec
[])
1045 for(m
= -D_BOX_Z
; m
<= D_BOX_Z
; m
++)
1046 for(l
= -D_BOX_Y
; l
<= D_BOX_Y
; l
++)
1047 for(k
= -D_BOX_X
; k
<= D_BOX_X
; k
++,n
++) {
1048 test
= XYZ2IS(k
,l
,m
);
1050 gmx_incons("inconsistent shift numbering");
1051 for(d
= 0; d
< DIM
; d
++)
1052 shift_vec
[n
][d
] = k
*box
[XX
][d
] + l
*box
[YY
][d
] + m
*box
[ZZ
][d
];
1056 void calc_box_center(int ecenter
,matrix box
,rvec box_center
)
1060 clear_rvec(box_center
);
1063 for(m
=0; (m
<DIM
); m
++)
1064 for(d
=0; d
<DIM
; d
++)
1065 box_center
[d
] += 0.5*box
[m
][d
];
1068 for(d
=0; d
<DIM
; d
++)
1069 box_center
[d
] = 0.5*box
[d
][d
];
1074 gmx_fatal(FARGS
,"Unsupported value %d for ecenter",ecenter
);
1078 void calc_triclinic_images(matrix box
,rvec img
[])
1082 /* Calculate 3 adjacent images in the xy-plane */
1083 copy_rvec(box
[0],img
[0]);
1084 copy_rvec(box
[1],img
[1]);
1086 svmul(-1,img
[1],img
[1]);
1087 rvec_sub(img
[1],img
[0],img
[2]);
1089 /* Get the next 3 in the xy-plane as mirror images */
1091 svmul(-1,img
[i
],img
[3+i
]);
1093 /* Calculate the first 4 out of xy-plane images */
1094 copy_rvec(box
[2],img
[6]);
1096 svmul(-1,img
[6],img
[6]);
1098 rvec_add(img
[6],img
[i
+1],img
[7+i
]);
1100 /* Mirror the last 4 from the previous in opposite rotation */
1102 svmul(-1,img
[6 + (2+i
) % 4],img
[10+i
]);
1105 void calc_compact_unitcell_vertices(int ecenter
,matrix box
,rvec vert
[])
1107 rvec img
[NTRICIMG
],box_center
;
1110 calc_triclinic_images(box
,img
);
1113 for(i
=2; i
<=5; i
+=3) {
1121 for(j
=0; j
<4; j
++) {
1122 for(d
=0; d
<DIM
; d
++)
1123 vert
[n
][d
] = img
[i
][d
]+img
[tmp
[j
]][d
]+img
[tmp
[(j
+1)%4]][d
];
1127 for(i
=7; i
<=13; i
+=6) {
1135 for(j
=0; j
<4; j
++) {
1136 for(d
=0; d
<DIM
; d
++)
1137 vert
[n
][d
] = img
[i
][d
]+img
[tmp
[j
]][d
]+img
[tmp
[(j
+1)%4]][d
];
1141 for(i
=9; i
<=11; i
+=2) {
1152 for(j
=0; j
<4; j
++) {
1153 for(d
=0; d
<DIM
; d
++)
1154 vert
[n
][d
] = img
[i
][d
]+img
[tmp
[j
]][d
]+img
[tmp
[(j
+1)%4]][d
];
1159 calc_box_center(ecenter
,box
,box_center
);
1160 for(i
=0; i
<NCUCVERT
; i
++)
1161 for(d
=0; d
<DIM
; d
++)
1162 vert
[i
][d
] = vert
[i
][d
]*0.25+box_center
[d
];
1165 int *compact_unitcell_edges()
1167 /* this is an index in vert[] (see calc_box_vertices) */
1168 /*static int edge[NCUCEDGE*2];*/
1170 static const int hexcon
[24] = { 0,9, 1,19, 2,15, 3,21,
1171 4,17, 5,11, 6,23, 7,13,
1172 8,20, 10,18, 12,16, 14,22 };
1174 gmx_bool bFirst
= TRUE
;
1176 snew(edge
,NCUCEDGE
*2);
1181 for(j
=0; j
<4; j
++) {
1182 edge
[e
++] = 4*i
+ j
;
1183 edge
[e
++] = 4*i
+ (j
+1) % 4;
1185 for(i
=0; i
<12*2; i
++)
1186 edge
[e
++] = hexcon
[i
];
1194 void put_atoms_in_box_omp(int ePBC
,matrix box
,int natoms
,rvec x
[])
1197 nth
= gmx_omp_nthreads_get(emntDefault
);
1199 #pragma omp parallel for num_threads(nth) schedule(static)
1200 for(t
=0; t
<nth
; t
++)
1204 offset
= (natoms
*t
)/nth
;
1205 len
= (natoms
*(t
+ 1))/nth
- offset
;
1206 put_atoms_in_box(ePBC
, box
, len
, x
+ offset
);
1210 void put_atoms_in_box(int ePBC
,matrix box
,int natoms
,rvec x
[])
1214 if (ePBC
== epbcSCREW
)
1216 gmx_fatal(FARGS
,"Sorry, %s pbc is not yet supported",epbc_names
[ePBC
]);
1230 for(i
=0; (i
<natoms
); i
++)
1232 for(m
=npbcdim
-1; m
>=0; m
--) {
1237 x
[i
][d
] += box
[m
][d
];
1240 while (x
[i
][m
] >= box
[m
][m
])
1244 x
[i
][d
] -= box
[m
][d
];
1252 for(i
=0; i
<natoms
; i
++)
1254 for(d
=0; d
<npbcdim
; d
++) {
1257 x
[i
][d
] += box
[d
][d
];
1259 while (x
[i
][d
] >= box
[d
][d
])
1261 x
[i
][d
] -= box
[d
][d
];
1268 void put_atoms_in_triclinic_unitcell(int ecenter
,matrix box
,
1269 int natoms
,rvec x
[])
1271 rvec box_center
,shift_center
;
1272 real shm01
,shm02
,shm12
,shift
;
1275 calc_box_center(ecenter
,box
,box_center
);
1277 /* The product of matrix shm with a coordinate gives the shift vector
1278 which is required determine the periodic cell position */
1279 shm01
= box
[1][0]/box
[1][1];
1280 shm02
= (box
[1][1]*box
[2][0] - box
[2][1]*box
[1][0])/(box
[1][1]*box
[2][2]);
1281 shm12
= box
[2][1]/box
[2][2];
1283 clear_rvec(shift_center
);
1284 for(d
=0; d
<DIM
; d
++)
1285 rvec_inc(shift_center
,box
[d
]);
1286 svmul(0.5,shift_center
,shift_center
);
1287 rvec_sub(box_center
,shift_center
,shift_center
);
1289 shift_center
[0] = shm01
*shift_center
[1] + shm02
*shift_center
[2];
1290 shift_center
[1] = shm12
*shift_center
[2];
1291 shift_center
[2] = 0;
1293 for(i
=0; (i
<natoms
); i
++)
1294 for(m
=DIM
-1; m
>=0; m
--) {
1295 shift
= shift_center
[m
];
1297 shift
+= shm01
*x
[i
][1] + shm02
*x
[i
][2];
1298 } else if (m
== 1) {
1299 shift
+= shm12
*x
[i
][2];
1301 while (x
[i
][m
]-shift
< 0)
1303 x
[i
][d
] += box
[m
][d
];
1304 while (x
[i
][m
]-shift
>= box
[m
][m
])
1306 x
[i
][d
] -= box
[m
][d
];
1311 put_atoms_in_compact_unitcell(int ePBC
,int ecenter
,matrix box
,
1312 int natoms
,rvec x
[])
1318 set_pbc(&pbc
,ePBC
,box
);
1319 calc_box_center(ecenter
,box
,box_center
);
1320 for(i
=0; i
<natoms
; i
++) {
1321 pbc_dx(&pbc
,x
[i
],box_center
,dx
);
1322 rvec_add(box_center
,dx
,x
[i
]);
1325 return pbc
.bLimitDistance
?
1326 "WARNING: Could not put all atoms in the compact unitcell\n"