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 * Copyright (c) 2013,2014,2015,2016, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
39 * Implements routines in pbc.h.
41 * Utility functions for handling periodic boundary conditions.
42 * Mainly used in analysis tools.
52 #include "gromacs/math/functions.h"
53 #include "gromacs/math/units.h"
54 #include "gromacs/math/utilities.h"
55 #include "gromacs/math/vec.h"
56 #include "gromacs/math/vecdump.h"
57 #include "gromacs/mdtypes/inputrec.h"
58 #include "gromacs/pbcutil/ishift.h"
59 #include "gromacs/pbcutil/mshift.h"
60 #include "gromacs/utility/exceptions.h"
61 #include "gromacs/utility/fatalerror.h"
62 #include "gromacs/utility/gmxassert.h"
63 #include "gromacs/utility/smalloc.h"
65 const char *epbc_names[epbcNR+1] =
67 "xyz", "no", "xy", "screw", NULL
70 /* Skip 0 so we have more chance of detecting if we forgot to call set_pbc. */
72 epbcdxRECTANGULAR = 1, epbcdxTRICLINIC,
73 epbcdx2D_RECT, epbcdx2D_TRIC,
74 epbcdx1D_RECT, epbcdx1D_TRIC,
75 epbcdxSCREW_RECT, epbcdxSCREW_TRIC,
76 epbcdxNOPBC, epbcdxUNSUPPORTED
79 //! Margin factor for error message
80 #define BOX_MARGIN 1.0010
81 //! Margin correction if the box is too skewed
82 #define BOX_MARGIN_CORRECT 1.0005
84 int ePBC2npbcdim(int ePBC)
90 case epbcXYZ: npbcdim = 3; break;
91 case epbcXY: npbcdim = 2; break;
92 case epbcSCREW: npbcdim = 3; break;
93 case epbcNONE: npbcdim = 0; break;
94 default: gmx_fatal(FARGS, "Unknown ePBC=%d in ePBC2npbcdim", ePBC);
100 int inputrec2nboundeddim(const t_inputrec *ir)
102 if (ir->nwall == 2 && ir->ePBC == epbcXY)
108 return ePBC2npbcdim(ir->ePBC);
112 void dump_pbc(FILE *fp, t_pbc *pbc)
116 fprintf(fp, "ePBCDX = %d\n", pbc->ePBCDX);
117 pr_rvecs(fp, 0, "box", pbc->box, DIM);
118 pr_rvecs(fp, 0, "fbox_diag", &pbc->fbox_diag, 1);
119 pr_rvecs(fp, 0, "hbox_diag", &pbc->hbox_diag, 1);
120 pr_rvecs(fp, 0, "mhbox_diag", &pbc->mhbox_diag, 1);
121 rvec_add(pbc->hbox_diag, pbc->mhbox_diag, sum_box);
122 pr_rvecs(fp, 0, "sum of the above two", &sum_box, 1);
123 fprintf(fp, "max_cutoff2 = %g\n", pbc->max_cutoff2);
124 fprintf(fp, "ntric_vec = %d\n", pbc->ntric_vec);
125 if (pbc->ntric_vec > 0)
127 pr_ivecs(fp, 0, "tric_shift", pbc->tric_shift, pbc->ntric_vec, FALSE);
128 pr_rvecs(fp, 0, "tric_vec", pbc->tric_vec, pbc->ntric_vec);
132 const char *check_box(int ePBC, const matrix box)
138 ePBC = guess_ePBC(box);
141 if (ePBC == epbcNONE)
146 if ((box[XX][YY] != 0) || (box[XX][ZZ] != 0) || (box[YY][ZZ] != 0))
148 ptr = "Only triclinic boxes with the first vector parallel to the x-axis and the second vector in the xy-plane are supported.";
150 else if (ePBC == epbcSCREW && (box[YY][XX] != 0 || box[ZZ][XX] != 0))
152 ptr = "The unit cell can not have off-diagonal x-components with screw pbc";
154 else if (std::fabs(box[YY][XX]) > BOX_MARGIN*0.5*box[XX][XX] ||
156 (std::fabs(box[ZZ][XX]) > BOX_MARGIN*0.5*box[XX][XX] ||
157 std::fabs(box[ZZ][YY]) > BOX_MARGIN*0.5*box[YY][YY])))
159 ptr = "Triclinic box is too skewed.";
169 void matrix_convert(matrix box, const rvec vec, const rvec angleInDegrees)
172 svmul(DEG2RAD, angleInDegrees, angle);
173 box[XX][XX] = vec[XX];
174 box[YY][XX] = vec[YY]*cos(angle[ZZ]);
175 box[YY][YY] = vec[YY]*sin(angle[ZZ]);
176 box[ZZ][XX] = vec[ZZ]*cos(angle[YY]);
177 box[ZZ][YY] = vec[ZZ]
178 *(cos(angle[XX])-cos(angle[YY])*cos(angle[ZZ]))/sin(angle[ZZ]);
179 box[ZZ][ZZ] = sqrt(gmx::square(vec[ZZ])
180 -box[ZZ][XX]*box[ZZ][XX]-box[ZZ][YY]*box[ZZ][YY]);
183 real max_cutoff2(int ePBC, const matrix box)
185 real min_hv2, min_ss;
186 const real oneFourth = 0.25;
188 /* Physical limitation of the cut-off
189 * by half the length of the shortest box vector.
191 min_hv2 = oneFourth * std::min(norm2(box[XX]), norm2(box[YY]));
194 min_hv2 = std::min(min_hv2, oneFourth * norm2(box[ZZ]));
197 /* Limitation to the smallest diagonal element due to optimizations:
198 * checking only linear combinations of single box-vectors (2 in x)
199 * in the grid search and pbc_dx is a lot faster
200 * than checking all possible combinations.
204 min_ss = std::min(box[XX][XX], box[YY][YY]);
208 min_ss = std::min(box[XX][XX], std::min(box[YY][YY] - std::fabs(box[ZZ][YY]), box[ZZ][ZZ]));
211 return std::min(min_hv2, min_ss*min_ss);
214 //! Set to true if warning has been printed
215 static gmx_bool bWarnedGuess = FALSE;
217 int guess_ePBC(const matrix box)
221 if (box[XX][XX] > 0 && box[YY][YY] > 0 && box[ZZ][ZZ] > 0)
225 else if (box[XX][XX] > 0 && box[YY][YY] > 0 && box[ZZ][ZZ] == 0)
229 else if (box[XX][XX] == 0 && box[YY][YY] == 0 && box[ZZ][ZZ] == 0)
237 fprintf(stderr, "WARNING: Unsupported box diagonal %f %f %f, "
238 "will not use periodic boundary conditions\n\n",
239 box[XX][XX], box[YY][YY], box[ZZ][ZZ]);
247 fprintf(debug, "Guessed pbc = %s from the box matrix\n", epbc_names[ePBC]);
253 //! Check if the box still obeys the restrictions, if not, correct it
254 static int correct_box_elem(FILE *fplog, int step, tensor box, int v, int d)
256 int shift, maxshift = 10;
260 /* correct elem d of vector v with vector d */
261 while (box[v][d] > BOX_MARGIN_CORRECT*0.5*box[d][d])
265 fprintf(fplog, "Step %d: correcting invalid box:\n", step);
266 pr_rvecs(fplog, 0, "old box", box, DIM);
268 rvec_dec(box[v], box[d]);
272 pr_rvecs(fplog, 0, "new box", box, DIM);
274 if (shift <= -maxshift)
277 "Box was shifted at least %d times. Please see log-file.",
281 while (box[v][d] < -BOX_MARGIN_CORRECT*0.5*box[d][d])
285 fprintf(fplog, "Step %d: correcting invalid box:\n", step);
286 pr_rvecs(fplog, 0, "old box", box, DIM);
288 rvec_inc(box[v], box[d]);
292 pr_rvecs(fplog, 0, "new box", box, DIM);
294 if (shift >= maxshift)
297 "Box was shifted at least %d times. Please see log-file.",
305 gmx_bool correct_box(FILE *fplog, int step, tensor box, t_graph *graph)
310 zy = correct_box_elem(fplog, step, box, ZZ, YY);
311 zx = correct_box_elem(fplog, step, box, ZZ, XX);
312 yx = correct_box_elem(fplog, step, box, YY, XX);
314 bCorrected = (zy || zx || yx);
316 if (bCorrected && graph)
318 /* correct the graph */
319 for (i = graph->at_start; i < graph->at_end; i++)
321 graph->ishift[i][YY] -= graph->ishift[i][ZZ]*zy;
322 graph->ishift[i][XX] -= graph->ishift[i][ZZ]*zx;
323 graph->ishift[i][XX] -= graph->ishift[i][YY]*yx;
330 int ndof_com(t_inputrec *ir)
341 n = (ir->nwall == 0 ? 3 : 2);
347 gmx_incons("Unknown pbc in calc_nrdf");
353 //! Do the real arithmetic for filling the pbc struct
354 static void low_set_pbc(t_pbc *pbc, int ePBC,
355 const ivec dd_pbc, const matrix box)
357 int order[3] = { 0, -1, 1 };
362 pbc->ndim_ePBC = ePBC2npbcdim(ePBC);
364 if (pbc->ePBC == epbcNONE)
366 pbc->ePBCDX = epbcdxNOPBC;
371 copy_mat(box, pbc->box);
372 pbc->max_cutoff2 = 0;
376 for (int i = 0; (i < DIM); i++)
378 pbc->fbox_diag[i] = box[i][i];
379 pbc->hbox_diag[i] = pbc->fbox_diag[i]*0.5;
380 pbc->mhbox_diag[i] = -pbc->hbox_diag[i];
383 ptr = check_box(ePBC, box);
386 fprintf(stderr, "Warning: %s\n", ptr);
387 pr_rvecs(stderr, 0, " Box", box, DIM);
388 fprintf(stderr, " Can not fix pbc.\n\n");
389 pbc->ePBCDX = epbcdxUNSUPPORTED;
393 if (ePBC == epbcSCREW && NULL != dd_pbc)
395 /* This combinated should never appear here */
396 gmx_incons("low_set_pbc called with screw pbc and dd_nc != NULL");
400 for (int i = 0; i < DIM; i++)
402 if ((dd_pbc && dd_pbc[i] == 0) || (ePBC == epbcXY && i == ZZ))
415 /* 1D pbc is not an mdp option and it is therefore only used
416 * with single shifts.
418 pbc->ePBCDX = epbcdx1D_RECT;
419 for (int i = 0; i < DIM; i++)
426 GMX_ASSERT(pbc->dim < DIM, "Dimension for PBC incorrect");
427 for (int i = 0; i < pbc->dim; i++)
429 if (pbc->box[pbc->dim][i] != 0)
431 pbc->ePBCDX = epbcdx1D_TRIC;
436 pbc->ePBCDX = epbcdx2D_RECT;
437 for (int i = 0; i < DIM; i++)
444 for (int i = 0; i < DIM; i++)
448 for (int j = 0; j < i; j++)
450 if (pbc->box[i][j] != 0)
452 pbc->ePBCDX = epbcdx2D_TRIC;
459 if (ePBC != epbcSCREW)
463 pbc->ePBCDX = epbcdxTRICLINIC;
467 pbc->ePBCDX = epbcdxRECTANGULAR;
472 pbc->ePBCDX = (box[ZZ][YY] == 0 ? epbcdxSCREW_RECT : epbcdxSCREW_TRIC);
473 if (pbc->ePBCDX == epbcdxSCREW_TRIC)
476 "Screw pbc is not yet implemented for triclinic boxes.\n"
477 "Can not fix pbc.\n");
478 pbc->ePBCDX = epbcdxUNSUPPORTED;
483 gmx_fatal(FARGS, "Incorrect number of pbc dimensions with DD: %d",
486 pbc->max_cutoff2 = max_cutoff2(ePBC, box);
488 if (pbc->ePBCDX == epbcdxTRICLINIC ||
489 pbc->ePBCDX == epbcdx2D_TRIC ||
490 pbc->ePBCDX == epbcdxSCREW_TRIC)
494 pr_rvecs(debug, 0, "Box", box, DIM);
495 fprintf(debug, "max cutoff %.3f\n", sqrt(pbc->max_cutoff2));
497 /* We will only need single shifts here */
498 for (int kk = 0; kk < 3; kk++)
501 if (!bPBC[ZZ] && k != 0)
505 for (int jj = 0; jj < 3; jj++)
508 if (!bPBC[YY] && j != 0)
512 for (int ii = 0; ii < 3; ii++)
515 if (!bPBC[XX] && i != 0)
519 /* A shift is only useful when it is trilinic */
520 if (j != 0 || k != 0)
527 for (int d = 0; d < DIM; d++)
529 trial[d] = i*box[XX][d] + j*box[YY][d] + k*box[ZZ][d];
530 /* Choose the vector within the brick around 0,0,0 that
531 * will become the shortest due to shift try.
542 pos[d] = std::min( pbc->hbox_diag[d], -trial[d]);
546 pos[d] = std::max(-pbc->hbox_diag[d], -trial[d]);
549 d2old += gmx::square(pos[d]);
550 d2new += gmx::square(pos[d] + trial[d]);
552 if (BOX_MARGIN*d2new < d2old)
554 /* Check if shifts with one box vector less do better */
555 gmx_bool bUse = TRUE;
556 for (int dd = 0; dd < DIM; dd++)
558 int shift = (dd == 0 ? i : (dd == 1 ? j : k));
562 for (int d = 0; d < DIM; d++)
564 d2new_c += gmx::square(pos[d] + trial[d] - shift*box[dd][d]);
566 if (d2new_c <= BOX_MARGIN*d2new)
574 /* Accept this shift vector. */
575 if (pbc->ntric_vec >= MAX_NTRICVEC)
577 fprintf(stderr, "\nWARNING: Found more than %d triclinic correction vectors, ignoring some.\n"
578 " There is probably something wrong with your box.\n", MAX_NTRICVEC);
579 pr_rvecs(stderr, 0, " Box", box, DIM);
583 copy_rvec(trial, pbc->tric_vec[pbc->ntric_vec]);
584 pbc->tric_shift[pbc->ntric_vec][XX] = i;
585 pbc->tric_shift[pbc->ntric_vec][YY] = j;
586 pbc->tric_shift[pbc->ntric_vec][ZZ] = k;
591 fprintf(debug, " tricvec %2d = %2d %2d %2d %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
592 pbc->ntric_vec, i, j, k,
593 sqrt(d2old), sqrt(d2new),
594 trial[XX], trial[YY], trial[ZZ],
595 pos[XX], pos[YY], pos[ZZ]);
608 void set_pbc(t_pbc *pbc, int ePBC, const matrix box)
612 ePBC = guess_ePBC(box);
615 low_set_pbc(pbc, ePBC, NULL, box);
618 t_pbc *set_pbc_dd(t_pbc *pbc, int ePBC,
619 const ivec domdecCells,
620 gmx_bool bSingleDir, const matrix box)
622 if (ePBC == epbcNONE)
629 if (nullptr == domdecCells)
631 low_set_pbc(pbc, ePBC, NULL, box);
635 if (ePBC == epbcSCREW && domdecCells[XX] > 1)
637 /* The rotation has been taken care of during coordinate communication */
643 for (int i = 0; i < DIM; i++)
646 if (domdecCells[i] <= (bSingleDir ? 1 : 2) &&
647 !(ePBC == epbcXY && i == ZZ))
656 low_set_pbc(pbc, ePBC, usePBC, box);
660 pbc->ePBC = epbcNONE;
664 return (pbc->ePBC != epbcNONE ? pbc : NULL);
667 void pbc_dx(const t_pbc *pbc, const rvec x1, const rvec x2, rvec dx)
670 rvec dx_start, trial;
674 rvec_sub(x1, x2, dx);
678 case epbcdxRECTANGULAR:
679 for (i = 0; i < DIM; i++)
681 while (dx[i] > pbc->hbox_diag[i])
683 dx[i] -= pbc->fbox_diag[i];
685 while (dx[i] <= pbc->mhbox_diag[i])
687 dx[i] += pbc->fbox_diag[i];
691 case epbcdxTRICLINIC:
692 for (i = DIM-1; i >= 0; i--)
694 while (dx[i] > pbc->hbox_diag[i])
696 for (j = i; j >= 0; j--)
698 dx[j] -= pbc->box[i][j];
701 while (dx[i] <= pbc->mhbox_diag[i])
703 for (j = i; j >= 0; j--)
705 dx[j] += pbc->box[i][j];
709 /* dx is the distance in a rectangular box */
711 if (d2min > pbc->max_cutoff2)
713 copy_rvec(dx, dx_start);
715 /* Now try all possible shifts, when the distance is within max_cutoff
716 * it must be the shortest possible distance.
719 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
721 rvec_add(dx_start, pbc->tric_vec[i], trial);
722 d2trial = norm2(trial);
725 copy_rvec(trial, dx);
733 for (i = 0; i < DIM; i++)
737 while (dx[i] > pbc->hbox_diag[i])
739 dx[i] -= pbc->fbox_diag[i];
741 while (dx[i] <= pbc->mhbox_diag[i])
743 dx[i] += pbc->fbox_diag[i];
750 for (i = DIM-1; i >= 0; i--)
754 while (dx[i] > pbc->hbox_diag[i])
756 for (j = i; j >= 0; j--)
758 dx[j] -= pbc->box[i][j];
761 while (dx[i] <= pbc->mhbox_diag[i])
763 for (j = i; j >= 0; j--)
765 dx[j] += pbc->box[i][j];
768 d2min += dx[i]*dx[i];
771 if (d2min > pbc->max_cutoff2)
773 copy_rvec(dx, dx_start);
775 /* Now try all possible shifts, when the distance is within max_cutoff
776 * it must be the shortest possible distance.
779 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
781 rvec_add(dx_start, pbc->tric_vec[i], trial);
783 for (j = 0; j < DIM; j++)
787 d2trial += trial[j]*trial[j];
792 copy_rvec(trial, dx);
799 case epbcdxSCREW_RECT:
800 /* The shift definition requires x first */
802 while (dx[XX] > pbc->hbox_diag[XX])
804 dx[XX] -= pbc->fbox_diag[XX];
807 while (dx[XX] <= pbc->mhbox_diag[XX])
809 dx[XX] += pbc->fbox_diag[YY];
814 /* Rotate around the x-axis in the middle of the box */
815 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
816 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
818 /* Normal pbc for y and z */
819 for (i = YY; i <= ZZ; i++)
821 while (dx[i] > pbc->hbox_diag[i])
823 dx[i] -= pbc->fbox_diag[i];
825 while (dx[i] <= pbc->mhbox_diag[i])
827 dx[i] += pbc->fbox_diag[i];
832 case epbcdxUNSUPPORTED:
835 gmx_fatal(FARGS, "Internal error in pbc_dx, set_pbc has not been called");
840 int pbc_dx_aiuc(const t_pbc *pbc, const rvec x1, const rvec x2, rvec dx)
843 rvec dx_start, trial;
845 ivec ishift, ishift_start;
847 rvec_sub(x1, x2, dx);
852 case epbcdxRECTANGULAR:
853 for (i = 0; i < DIM; i++)
855 if (dx[i] > pbc->hbox_diag[i])
857 dx[i] -= pbc->fbox_diag[i];
860 else if (dx[i] <= pbc->mhbox_diag[i])
862 dx[i] += pbc->fbox_diag[i];
867 case epbcdxTRICLINIC:
868 /* For triclinic boxes the performance difference between
869 * if/else and two while loops is negligible.
870 * However, the while version can cause extreme delays
871 * before a simulation crashes due to large forces which
872 * can cause unlimited displacements.
873 * Also allowing multiple shifts would index fshift beyond bounds.
875 for (i = DIM-1; i >= 1; i--)
877 if (dx[i] > pbc->hbox_diag[i])
879 for (j = i; j >= 0; j--)
881 dx[j] -= pbc->box[i][j];
885 else if (dx[i] <= pbc->mhbox_diag[i])
887 for (j = i; j >= 0; j--)
889 dx[j] += pbc->box[i][j];
894 /* Allow 2 shifts in x */
895 if (dx[XX] > pbc->hbox_diag[XX])
897 dx[XX] -= pbc->fbox_diag[XX];
899 if (dx[XX] > pbc->hbox_diag[XX])
901 dx[XX] -= pbc->fbox_diag[XX];
905 else if (dx[XX] <= pbc->mhbox_diag[XX])
907 dx[XX] += pbc->fbox_diag[XX];
909 if (dx[XX] <= pbc->mhbox_diag[XX])
911 dx[XX] += pbc->fbox_diag[XX];
915 /* dx is the distance in a rectangular box */
917 if (d2min > pbc->max_cutoff2)
919 copy_rvec(dx, dx_start);
920 copy_ivec(ishift, ishift_start);
922 /* Now try all possible shifts, when the distance is within max_cutoff
923 * it must be the shortest possible distance.
926 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
928 rvec_add(dx_start, pbc->tric_vec[i], trial);
929 d2trial = norm2(trial);
932 copy_rvec(trial, dx);
933 ivec_add(ishift_start, pbc->tric_shift[i], ishift);
941 for (i = 0; i < DIM; i++)
945 if (dx[i] > pbc->hbox_diag[i])
947 dx[i] -= pbc->fbox_diag[i];
950 else if (dx[i] <= pbc->mhbox_diag[i])
952 dx[i] += pbc->fbox_diag[i];
960 for (i = DIM-1; i >= 1; i--)
964 if (dx[i] > pbc->hbox_diag[i])
966 for (j = i; j >= 0; j--)
968 dx[j] -= pbc->box[i][j];
972 else if (dx[i] <= pbc->mhbox_diag[i])
974 for (j = i; j >= 0; j--)
976 dx[j] += pbc->box[i][j];
980 d2min += dx[i]*dx[i];
985 /* Allow 2 shifts in x */
986 if (dx[XX] > pbc->hbox_diag[XX])
988 dx[XX] -= pbc->fbox_diag[XX];
990 if (dx[XX] > pbc->hbox_diag[XX])
992 dx[XX] -= pbc->fbox_diag[XX];
996 else if (dx[XX] <= pbc->mhbox_diag[XX])
998 dx[XX] += pbc->fbox_diag[XX];
1000 if (dx[XX] <= pbc->mhbox_diag[XX])
1002 dx[XX] += pbc->fbox_diag[XX];
1006 d2min += dx[XX]*dx[XX];
1008 if (d2min > pbc->max_cutoff2)
1010 copy_rvec(dx, dx_start);
1011 copy_ivec(ishift, ishift_start);
1012 /* Now try all possible shifts, when the distance is within max_cutoff
1013 * it must be the shortest possible distance.
1016 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
1018 rvec_add(dx_start, pbc->tric_vec[i], trial);
1020 for (j = 0; j < DIM; j++)
1024 d2trial += trial[j]*trial[j];
1027 if (d2trial < d2min)
1029 copy_rvec(trial, dx);
1030 ivec_add(ishift_start, pbc->tric_shift[i], ishift);
1039 if (dx[i] > pbc->hbox_diag[i])
1041 dx[i] -= pbc->fbox_diag[i];
1044 else if (dx[i] <= pbc->mhbox_diag[i])
1046 dx[i] += pbc->fbox_diag[i];
1052 if (dx[i] > pbc->hbox_diag[i])
1054 rvec_dec(dx, pbc->box[i]);
1057 else if (dx[i] <= pbc->mhbox_diag[i])
1059 rvec_inc(dx, pbc->box[i]);
1063 case epbcdxSCREW_RECT:
1064 /* The shift definition requires x first */
1065 if (dx[XX] > pbc->hbox_diag[XX])
1067 dx[XX] -= pbc->fbox_diag[XX];
1070 else if (dx[XX] <= pbc->mhbox_diag[XX])
1072 dx[XX] += pbc->fbox_diag[XX];
1075 if (ishift[XX] == 1 || ishift[XX] == -1)
1077 /* Rotate around the x-axis in the middle of the box */
1078 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
1079 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
1081 /* Normal pbc for y and z */
1082 for (i = YY; i <= ZZ; i++)
1084 if (dx[i] > pbc->hbox_diag[i])
1086 dx[i] -= pbc->fbox_diag[i];
1089 else if (dx[i] <= pbc->mhbox_diag[i])
1091 dx[i] += pbc->fbox_diag[i];
1097 case epbcdxUNSUPPORTED:
1100 gmx_fatal(FARGS, "Internal error in pbc_dx_aiuc, set_pbc_dd or set_pbc has not been called");
1104 is = IVEC2IS(ishift);
1107 range_check_mesg(is, 0, SHIFTS, "PBC shift vector index range check.");
1113 //! Compute distance vector in double precision
1114 void pbc_dx_d(const t_pbc *pbc, const dvec x1, const dvec x2, dvec dx)
1117 dvec dx_start, trial;
1118 double d2min, d2trial;
1121 dvec_sub(x1, x2, dx);
1123 switch (pbc->ePBCDX)
1125 case epbcdxRECTANGULAR:
1127 for (i = 0; i < DIM; i++)
1131 while (dx[i] > pbc->hbox_diag[i])
1133 dx[i] -= pbc->fbox_diag[i];
1135 while (dx[i] <= pbc->mhbox_diag[i])
1137 dx[i] += pbc->fbox_diag[i];
1142 case epbcdxTRICLINIC:
1145 for (i = DIM-1; i >= 0; i--)
1149 while (dx[i] > pbc->hbox_diag[i])
1151 for (j = i; j >= 0; j--)
1153 dx[j] -= pbc->box[i][j];
1156 while (dx[i] <= pbc->mhbox_diag[i])
1158 for (j = i; j >= 0; j--)
1160 dx[j] += pbc->box[i][j];
1163 d2min += dx[i]*dx[i];
1166 if (d2min > pbc->max_cutoff2)
1168 copy_dvec(dx, dx_start);
1169 /* Now try all possible shifts, when the distance is within max_cutoff
1170 * it must be the shortest possible distance.
1173 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
1175 for (j = 0; j < DIM; j++)
1177 trial[j] = dx_start[j] + pbc->tric_vec[i][j];
1180 for (j = 0; j < DIM; j++)
1184 d2trial += trial[j]*trial[j];
1187 if (d2trial < d2min)
1189 copy_dvec(trial, dx);
1196 case epbcdxSCREW_RECT:
1197 /* The shift definition requires x first */
1199 while (dx[XX] > pbc->hbox_diag[XX])
1201 dx[XX] -= pbc->fbox_diag[XX];
1204 while (dx[XX] <= pbc->mhbox_diag[XX])
1206 dx[XX] += pbc->fbox_diag[YY];
1211 /* Rotate around the x-axis in the middle of the box */
1212 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
1213 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
1215 /* Normal pbc for y and z */
1216 for (i = YY; i <= ZZ; i++)
1218 while (dx[i] > pbc->hbox_diag[i])
1220 dx[i] -= pbc->fbox_diag[i];
1222 while (dx[i] <= pbc->mhbox_diag[i])
1224 dx[i] += pbc->fbox_diag[i];
1229 case epbcdxUNSUPPORTED:
1232 gmx_fatal(FARGS, "Internal error in pbc_dx, set_pbc has not been called");
1237 void calc_shifts(const matrix box, rvec shift_vec[])
1239 int k, l, m, d, n, test;
1242 for (m = -D_BOX_Z; m <= D_BOX_Z; m++)
1244 for (l = -D_BOX_Y; l <= D_BOX_Y; l++)
1246 for (k = -D_BOX_X; k <= D_BOX_X; k++, n++)
1248 test = XYZ2IS(k, l, m);
1251 gmx_incons("inconsistent shift numbering");
1253 for (d = 0; d < DIM; d++)
1255 shift_vec[n][d] = k*box[XX][d] + l*box[YY][d] + m*box[ZZ][d];
1262 void calc_box_center(int ecenter, const matrix box, rvec box_center)
1266 clear_rvec(box_center);
1270 for (m = 0; (m < DIM); m++)
1272 for (d = 0; d < DIM; d++)
1274 box_center[d] += 0.5*box[m][d];
1279 for (d = 0; d < DIM; d++)
1281 box_center[d] = 0.5*box[d][d];
1287 gmx_fatal(FARGS, "Unsupported value %d for ecenter", ecenter);
1291 void calc_triclinic_images(const matrix box, rvec img[])
1295 /* Calculate 3 adjacent images in the xy-plane */
1296 copy_rvec(box[0], img[0]);
1297 copy_rvec(box[1], img[1]);
1300 svmul(-1, img[1], img[1]);
1302 rvec_sub(img[1], img[0], img[2]);
1304 /* Get the next 3 in the xy-plane as mirror images */
1305 for (i = 0; i < 3; i++)
1307 svmul(-1, img[i], img[3+i]);
1310 /* Calculate the first 4 out of xy-plane images */
1311 copy_rvec(box[2], img[6]);
1314 svmul(-1, img[6], img[6]);
1316 for (i = 0; i < 3; i++)
1318 rvec_add(img[6], img[i+1], img[7+i]);
1321 /* Mirror the last 4 from the previous in opposite rotation */
1322 for (i = 0; i < 4; i++)
1324 svmul(-1, img[6 + (2+i) % 4], img[10+i]);
1328 void calc_compact_unitcell_vertices(int ecenter, const matrix box, rvec vert[])
1330 rvec img[NTRICIMG], box_center;
1331 int n, i, j, tmp[4], d;
1332 const real oneFourth = 0.25;
1334 calc_triclinic_images(box, img);
1337 for (i = 2; i <= 5; i += 3)
1350 for (j = 0; j < 4; j++)
1352 for (d = 0; d < DIM; d++)
1354 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1359 for (i = 7; i <= 13; i += 6)
1372 for (j = 0; j < 4; j++)
1374 for (d = 0; d < DIM; d++)
1376 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1381 for (i = 9; i <= 11; i += 2)
1401 for (j = 0; j < 4; j++)
1403 for (d = 0; d < DIM; d++)
1405 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1411 calc_box_center(ecenter, box, box_center);
1412 for (i = 0; i < NCUCVERT; i++)
1414 for (d = 0; d < DIM; d++)
1416 vert[i][d] = vert[i][d]*oneFourth+box_center[d];
1421 int *compact_unitcell_edges()
1423 /* this is an index in vert[] (see calc_box_vertices) */
1424 /*static int edge[NCUCEDGE*2];*/
1426 static const int hexcon[24] = {
1427 0, 9, 1, 19, 2, 15, 3, 21,
1428 4, 17, 5, 11, 6, 23, 7, 13,
1429 8, 20, 10, 18, 12, 16, 14, 22
1433 snew(edge, NCUCEDGE*2);
1436 for (i = 0; i < 6; i++)
1438 for (j = 0; j < 4; j++)
1440 edge[e++] = 4*i + j;
1441 edge[e++] = 4*i + (j+1) % 4;
1444 for (i = 0; i < 12*2; i++)
1446 edge[e++] = hexcon[i];
1452 void put_atoms_in_box(int ePBC, const matrix box, int natoms, rvec x[])
1454 int npbcdim, i, m, d;
1456 if (ePBC == epbcSCREW)
1458 gmx_fatal(FARGS, "Sorry, %s pbc is not yet supported", epbc_names[ePBC]);
1472 for (i = 0; (i < natoms); i++)
1474 for (m = npbcdim-1; m >= 0; m--)
1478 for (d = 0; d <= m; d++)
1480 x[i][d] += box[m][d];
1483 while (x[i][m] >= box[m][m])
1485 for (d = 0; d <= m; d++)
1487 x[i][d] -= box[m][d];
1495 for (i = 0; i < natoms; i++)
1497 for (d = 0; d < npbcdim; d++)
1501 x[i][d] += box[d][d];
1503 while (x[i][d] >= box[d][d])
1505 x[i][d] -= box[d][d];
1512 void put_atoms_in_triclinic_unitcell(int ecenter, const matrix box,
1513 int natoms, rvec x[])
1515 rvec box_center, shift_center;
1516 real shm01, shm02, shm12, shift;
1519 calc_box_center(ecenter, box, box_center);
1521 /* The product of matrix shm with a coordinate gives the shift vector
1522 which is required determine the periodic cell position */
1523 shm01 = box[1][0]/box[1][1];
1524 shm02 = (box[1][1]*box[2][0] - box[2][1]*box[1][0])/(box[1][1]*box[2][2]);
1525 shm12 = box[2][1]/box[2][2];
1527 clear_rvec(shift_center);
1528 for (d = 0; d < DIM; d++)
1530 rvec_inc(shift_center, box[d]);
1532 svmul(0.5, shift_center, shift_center);
1533 rvec_sub(box_center, shift_center, shift_center);
1535 shift_center[0] = shm01*shift_center[1] + shm02*shift_center[2];
1536 shift_center[1] = shm12*shift_center[2];
1537 shift_center[2] = 0;
1539 for (i = 0; (i < natoms); i++)
1541 for (m = DIM-1; m >= 0; m--)
1543 shift = shift_center[m];
1546 shift += shm01*x[i][1] + shm02*x[i][2];
1550 shift += shm12*x[i][2];
1552 while (x[i][m]-shift < 0)
1554 for (d = 0; d <= m; d++)
1556 x[i][d] += box[m][d];
1559 while (x[i][m]-shift >= box[m][m])
1561 for (d = 0; d <= m; d++)
1563 x[i][d] -= box[m][d];
1570 void put_atoms_in_compact_unitcell(int ePBC, int ecenter, const matrix box,
1571 int natoms, rvec x[])
1574 rvec box_center, dx;
1577 set_pbc(&pbc, ePBC, box);
1579 if (pbc.ePBCDX == epbcdxUNSUPPORTED)
1581 gmx_fatal(FARGS, "Can not put atoms in compact unitcell with unsupported PBC");
1584 calc_box_center(ecenter, box, box_center);
1585 for (i = 0; i < natoms; i++)
1587 pbc_dx(&pbc, x[i], box_center, dx);
1588 rvec_add(box_center, dx, x[i]);