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,2017,2018,2019, 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/pbcutil/ishift.h"
58 #include "gromacs/pbcutil/mshift.h"
59 #include "gromacs/topology/topology.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] = { "xyz", "no", "xy", "screw", nullptr };
67 /* Skip 0 so we have more chance of detecting if we forgot to call set_pbc. */
70 epbcdxRECTANGULAR = 1,
82 //! Margin factor for error message
83 #define BOX_MARGIN 1.0010
84 //! Margin correction if the box is too skewed
85 #define BOX_MARGIN_CORRECT 1.0005
87 int ePBC2npbcdim(int ePBC)
93 case epbcXYZ: npbcdim = 3; break;
94 case epbcXY: npbcdim = 2; break;
95 case epbcSCREW: npbcdim = 3; break;
96 case epbcNONE: npbcdim = 0; break;
97 default: gmx_fatal(FARGS, "Unknown ePBC=%d in ePBC2npbcdim", ePBC);
103 void dump_pbc(FILE* fp, t_pbc* pbc)
107 fprintf(fp, "ePBCDX = %d\n", pbc->ePBCDX);
108 pr_rvecs(fp, 0, "box", pbc->box, DIM);
109 pr_rvecs(fp, 0, "fbox_diag", &pbc->fbox_diag, 1);
110 pr_rvecs(fp, 0, "hbox_diag", &pbc->hbox_diag, 1);
111 pr_rvecs(fp, 0, "mhbox_diag", &pbc->mhbox_diag, 1);
112 rvec_add(pbc->hbox_diag, pbc->mhbox_diag, sum_box);
113 pr_rvecs(fp, 0, "sum of the above two", &sum_box, 1);
114 fprintf(fp, "max_cutoff2 = %g\n", pbc->max_cutoff2);
115 fprintf(fp, "ntric_vec = %d\n", pbc->ntric_vec);
116 if (pbc->ntric_vec > 0)
118 pr_ivecs(fp, 0, "tric_shift", pbc->tric_shift, pbc->ntric_vec, FALSE);
119 pr_rvecs(fp, 0, "tric_vec", pbc->tric_vec, pbc->ntric_vec);
123 const char* check_box(int ePBC, const matrix box)
129 ePBC = guess_ePBC(box);
132 if (ePBC == epbcNONE)
137 if ((box[XX][YY] != 0) || (box[XX][ZZ] != 0) || (box[YY][ZZ] != 0))
139 ptr = "Only triclinic boxes with the first vector parallel to the x-axis and the second "
140 "vector in the xy-plane are supported.";
142 else if (ePBC == epbcSCREW && (box[YY][XX] != 0 || box[ZZ][XX] != 0))
144 ptr = "The unit cell can not have off-diagonal x-components with screw pbc";
146 else if (std::fabs(box[YY][XX]) > BOX_MARGIN * 0.5 * box[XX][XX]
148 && (std::fabs(box[ZZ][XX]) > BOX_MARGIN * 0.5 * box[XX][XX]
149 || std::fabs(box[ZZ][YY]) > BOX_MARGIN * 0.5 * box[YY][YY])))
151 ptr = "Triclinic box is too skewed.";
161 void matrix_convert(matrix box, const rvec vec, const rvec angleInDegrees)
164 svmul(DEG2RAD, angleInDegrees, angle);
165 box[XX][XX] = vec[XX];
166 box[YY][XX] = vec[YY] * cos(angle[ZZ]);
167 box[YY][YY] = vec[YY] * sin(angle[ZZ]);
168 box[ZZ][XX] = vec[ZZ] * cos(angle[YY]);
169 box[ZZ][YY] = vec[ZZ] * (cos(angle[XX]) - cos(angle[YY]) * cos(angle[ZZ])) / sin(angle[ZZ]);
171 std::sqrt(gmx::square(vec[ZZ]) - box[ZZ][XX] * box[ZZ][XX] - box[ZZ][YY] * box[ZZ][YY]);
174 real max_cutoff2(int ePBC, const matrix box)
176 real min_hv2, min_ss;
177 const real oneFourth = 0.25;
179 /* Physical limitation of the cut-off
180 * by half the length of the shortest box vector.
182 min_hv2 = oneFourth * std::min(norm2(box[XX]), norm2(box[YY]));
185 min_hv2 = std::min(min_hv2, oneFourth * norm2(box[ZZ]));
188 /* Limitation to the smallest diagonal element due to optimizations:
189 * checking only linear combinations of single box-vectors (2 in x)
190 * in the grid search and pbc_dx is a lot faster
191 * than checking all possible combinations.
195 min_ss = std::min(box[XX][XX], box[YY][YY]);
199 min_ss = std::min(box[XX][XX], std::min(box[YY][YY] - std::fabs(box[ZZ][YY]), box[ZZ][ZZ]));
202 return std::min(min_hv2, min_ss * min_ss);
205 //! Set to true if warning has been printed
206 static gmx_bool bWarnedGuess = FALSE;
208 int guess_ePBC(const matrix box)
212 if (box[XX][XX] > 0 && box[YY][YY] > 0 && box[ZZ][ZZ] > 0)
216 else if (box[XX][XX] > 0 && box[YY][YY] > 0 && box[ZZ][ZZ] == 0)
220 else if (box[XX][XX] == 0 && box[YY][YY] == 0 && box[ZZ][ZZ] == 0)
229 "WARNING: Unsupported box diagonal %f %f %f, "
230 "will not use periodic boundary conditions\n\n",
231 box[XX][XX], box[YY][YY], box[ZZ][ZZ]);
239 fprintf(debug, "Guessed pbc = %s from the box matrix\n", epbc_names[ePBC]);
245 //! Check if the box still obeys the restrictions, if not, correct it
246 static int correct_box_elem(FILE* fplog, int step, tensor box, int v, int d)
248 int shift, maxshift = 10;
252 /* correct elem d of vector v with vector d */
253 while (box[v][d] > BOX_MARGIN_CORRECT * 0.5 * box[d][d])
257 fprintf(fplog, "Step %d: correcting invalid box:\n", step);
258 pr_rvecs(fplog, 0, "old box", box, DIM);
260 rvec_dec(box[v], box[d]);
264 pr_rvecs(fplog, 0, "new box", box, DIM);
266 if (shift <= -maxshift)
268 gmx_fatal(FARGS, "Box was shifted at least %d times. Please see log-file.", maxshift);
271 while (box[v][d] < -BOX_MARGIN_CORRECT * 0.5 * box[d][d])
275 fprintf(fplog, "Step %d: correcting invalid box:\n", step);
276 pr_rvecs(fplog, 0, "old box", box, DIM);
278 rvec_inc(box[v], box[d]);
282 pr_rvecs(fplog, 0, "new box", box, DIM);
284 if (shift >= maxshift)
286 gmx_fatal(FARGS, "Box was shifted at least %d times. Please see log-file.", maxshift);
293 gmx_bool correct_box(FILE* fplog, int step, tensor box, t_graph* graph)
298 zy = correct_box_elem(fplog, step, box, ZZ, YY);
299 zx = correct_box_elem(fplog, step, box, ZZ, XX);
300 yx = correct_box_elem(fplog, step, box, YY, XX);
302 bCorrected = ((zy != 0) || (zx != 0) || (yx != 0));
304 if (bCorrected && graph)
306 /* correct the graph */
307 for (i = graph->at_start; i < graph->at_end; i++)
309 graph->ishift[i][YY] -= graph->ishift[i][ZZ] * zy;
310 graph->ishift[i][XX] -= graph->ishift[i][ZZ] * zx;
311 graph->ishift[i][XX] -= graph->ishift[i][YY] * yx;
318 //! Do the real arithmetic for filling the pbc struct
319 static void low_set_pbc(t_pbc* pbc, int ePBC, const ivec dd_pbc, const matrix box)
321 int order[3] = { 0, -1, 1 };
326 pbc->ndim_ePBC = ePBC2npbcdim(ePBC);
328 if (pbc->ePBC == epbcNONE)
330 pbc->ePBCDX = epbcdxNOPBC;
335 copy_mat(box, pbc->box);
336 pbc->max_cutoff2 = 0;
340 for (int i = 0; (i < DIM); i++)
342 pbc->fbox_diag[i] = box[i][i];
343 pbc->hbox_diag[i] = pbc->fbox_diag[i] * 0.5;
344 pbc->mhbox_diag[i] = -pbc->hbox_diag[i];
347 ptr = check_box(ePBC, box);
350 fprintf(stderr, "Warning: %s\n", ptr);
351 pr_rvecs(stderr, 0, " Box", box, DIM);
352 fprintf(stderr, " Can not fix pbc.\n\n");
353 pbc->ePBCDX = epbcdxUNSUPPORTED;
357 if (ePBC == epbcSCREW && nullptr != dd_pbc)
359 /* This combinated should never appear here */
360 gmx_incons("low_set_pbc called with screw pbc and dd_nc != NULL");
364 for (int i = 0; i < DIM; i++)
366 if ((dd_pbc && dd_pbc[i] == 0) || (ePBC == epbcXY && i == ZZ))
379 /* 1D pbc is not an mdp option and it is therefore only used
380 * with single shifts.
382 pbc->ePBCDX = epbcdx1D_RECT;
383 for (int i = 0; i < DIM; i++)
390 GMX_ASSERT(pbc->dim < DIM, "Dimension for PBC incorrect");
391 for (int i = 0; i < pbc->dim; i++)
393 if (pbc->box[pbc->dim][i] != 0)
395 pbc->ePBCDX = epbcdx1D_TRIC;
400 pbc->ePBCDX = epbcdx2D_RECT;
401 for (int i = 0; i < DIM; i++)
408 for (int i = 0; i < DIM; i++)
412 for (int j = 0; j < i; j++)
414 if (pbc->box[i][j] != 0)
416 pbc->ePBCDX = epbcdx2D_TRIC;
423 if (ePBC != epbcSCREW)
427 pbc->ePBCDX = epbcdxTRICLINIC;
431 pbc->ePBCDX = epbcdxRECTANGULAR;
436 pbc->ePBCDX = (box[ZZ][YY] == 0 ? epbcdxSCREW_RECT : epbcdxSCREW_TRIC);
437 if (pbc->ePBCDX == epbcdxSCREW_TRIC)
440 "Screw pbc is not yet implemented for triclinic boxes.\n"
441 "Can not fix pbc.\n");
442 pbc->ePBCDX = epbcdxUNSUPPORTED;
446 default: gmx_fatal(FARGS, "Incorrect number of pbc dimensions with DD: %d", npbcdim);
448 pbc->max_cutoff2 = max_cutoff2(ePBC, box);
450 if (pbc->ePBCDX == epbcdxTRICLINIC || pbc->ePBCDX == epbcdx2D_TRIC || pbc->ePBCDX == epbcdxSCREW_TRIC)
454 pr_rvecs(debug, 0, "Box", box, DIM);
455 fprintf(debug, "max cutoff %.3f\n", sqrt(pbc->max_cutoff2));
457 /* We will only need single shifts here */
458 for (int kk = 0; kk < 3; kk++)
461 if (!bPBC[ZZ] && k != 0)
465 for (int jj = 0; jj < 3; jj++)
468 if (!bPBC[YY] && j != 0)
472 for (int ii = 0; ii < 3; ii++)
475 if (!bPBC[XX] && i != 0)
479 /* A shift is only useful when it is trilinic */
480 if (j != 0 || k != 0)
487 for (int d = 0; d < DIM; d++)
489 trial[d] = i * box[XX][d] + j * box[YY][d] + k * box[ZZ][d];
490 /* Choose the vector within the brick around 0,0,0 that
491 * will become the shortest due to shift try.
502 pos[d] = std::min(pbc->hbox_diag[d], -trial[d]);
506 pos[d] = std::max(-pbc->hbox_diag[d], -trial[d]);
509 d2old += gmx::square(pos[d]);
510 d2new += gmx::square(pos[d] + trial[d]);
512 if (BOX_MARGIN * d2new < d2old)
514 /* Check if shifts with one box vector less do better */
515 gmx_bool bUse = TRUE;
516 for (int dd = 0; dd < DIM; dd++)
518 int shift = (dd == 0 ? i : (dd == 1 ? j : k));
522 for (int d = 0; d < DIM; d++)
524 d2new_c += gmx::square(pos[d] + trial[d] - shift * box[dd][d]);
526 if (d2new_c <= BOX_MARGIN * d2new)
534 /* Accept this shift vector. */
535 if (pbc->ntric_vec >= MAX_NTRICVEC)
538 "\nWARNING: Found more than %d triclinic "
539 "correction vectors, ignoring some.\n"
540 " There is probably something wrong with your "
543 pr_rvecs(stderr, 0, " Box", box, DIM);
547 copy_rvec(trial, pbc->tric_vec[pbc->ntric_vec]);
548 pbc->tric_shift[pbc->ntric_vec][XX] = i;
549 pbc->tric_shift[pbc->ntric_vec][YY] = j;
550 pbc->tric_shift[pbc->ntric_vec][ZZ] = k;
556 " tricvec %2d = %2d %2d %2d %5.2f %5.2f "
557 "%5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
558 pbc->ntric_vec, i, j, k, sqrt(d2old),
559 sqrt(d2new), trial[XX], trial[YY], trial[ZZ],
560 pos[XX], pos[YY], pos[ZZ]);
573 void set_pbc(t_pbc* pbc, int ePBC, const matrix box)
577 ePBC = guess_ePBC(box);
580 low_set_pbc(pbc, ePBC, nullptr, box);
583 t_pbc* set_pbc_dd(t_pbc* pbc, int ePBC, const ivec domdecCells, gmx_bool bSingleDir, const matrix box)
585 if (ePBC == epbcNONE)
592 if (nullptr == domdecCells)
594 low_set_pbc(pbc, ePBC, nullptr, box);
598 if (ePBC == epbcSCREW && domdecCells[XX] > 1)
600 /* The rotation has been taken care of during coordinate communication */
606 for (int i = 0; i < DIM; i++)
609 if (domdecCells[i] <= (bSingleDir ? 1 : 2) && !(ePBC == epbcXY && i == ZZ))
618 low_set_pbc(pbc, ePBC, usePBC, box);
622 pbc->ePBC = epbcNONE;
626 return (pbc->ePBC != epbcNONE ? pbc : nullptr);
629 void pbc_dx(const t_pbc* pbc, const rvec x1, const rvec x2, rvec dx)
632 rvec dx_start, trial;
636 rvec_sub(x1, x2, dx);
640 case epbcdxRECTANGULAR:
641 for (i = 0; i < DIM; i++)
643 while (dx[i] > pbc->hbox_diag[i])
645 dx[i] -= pbc->fbox_diag[i];
647 while (dx[i] <= pbc->mhbox_diag[i])
649 dx[i] += pbc->fbox_diag[i];
653 case epbcdxTRICLINIC:
654 for (i = DIM - 1; i >= 0; i--)
656 while (dx[i] > pbc->hbox_diag[i])
658 for (j = i; j >= 0; j--)
660 dx[j] -= pbc->box[i][j];
663 while (dx[i] <= pbc->mhbox_diag[i])
665 for (j = i; j >= 0; j--)
667 dx[j] += pbc->box[i][j];
671 /* dx is the distance in a rectangular box */
673 if (d2min > pbc->max_cutoff2)
675 copy_rvec(dx, dx_start);
677 /* Now try all possible shifts, when the distance is within max_cutoff
678 * it must be the shortest possible distance.
681 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
683 rvec_add(dx_start, pbc->tric_vec[i], trial);
684 d2trial = norm2(trial);
687 copy_rvec(trial, dx);
695 for (i = 0; i < DIM; i++)
699 while (dx[i] > pbc->hbox_diag[i])
701 dx[i] -= pbc->fbox_diag[i];
703 while (dx[i] <= pbc->mhbox_diag[i])
705 dx[i] += pbc->fbox_diag[i];
712 for (i = DIM - 1; i >= 0; i--)
716 while (dx[i] > pbc->hbox_diag[i])
718 for (j = i; j >= 0; j--)
720 dx[j] -= pbc->box[i][j];
723 while (dx[i] <= pbc->mhbox_diag[i])
725 for (j = i; j >= 0; j--)
727 dx[j] += pbc->box[i][j];
730 d2min += dx[i] * dx[i];
733 if (d2min > pbc->max_cutoff2)
735 copy_rvec(dx, dx_start);
737 /* Now try all possible shifts, when the distance is within max_cutoff
738 * it must be the shortest possible distance.
741 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
743 rvec_add(dx_start, pbc->tric_vec[i], trial);
745 for (j = 0; j < DIM; j++)
749 d2trial += trial[j] * trial[j];
754 copy_rvec(trial, dx);
761 case epbcdxSCREW_RECT:
762 /* The shift definition requires x first */
764 while (dx[XX] > pbc->hbox_diag[XX])
766 dx[XX] -= pbc->fbox_diag[XX];
769 while (dx[XX] <= pbc->mhbox_diag[XX])
771 dx[XX] += pbc->fbox_diag[YY];
776 /* Rotate around the x-axis in the middle of the box */
777 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
778 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
780 /* Normal pbc for y and z */
781 for (i = YY; i <= ZZ; i++)
783 while (dx[i] > pbc->hbox_diag[i])
785 dx[i] -= pbc->fbox_diag[i];
787 while (dx[i] <= pbc->mhbox_diag[i])
789 dx[i] += pbc->fbox_diag[i];
794 case epbcdxUNSUPPORTED: break;
795 default: gmx_fatal(FARGS, "Internal error in pbc_dx, set_pbc has not been called");
799 int pbc_dx_aiuc(const t_pbc* pbc, const rvec x1, const rvec x2, rvec dx)
802 rvec dx_start, trial;
804 ivec ishift, ishift_start;
806 rvec_sub(x1, x2, dx);
811 case epbcdxRECTANGULAR:
812 for (i = 0; i < DIM; i++)
814 if (dx[i] > pbc->hbox_diag[i])
816 dx[i] -= pbc->fbox_diag[i];
819 else if (dx[i] <= pbc->mhbox_diag[i])
821 dx[i] += pbc->fbox_diag[i];
826 case epbcdxTRICLINIC:
827 /* For triclinic boxes the performance difference between
828 * if/else and two while loops is negligible.
829 * However, the while version can cause extreme delays
830 * before a simulation crashes due to large forces which
831 * can cause unlimited displacements.
832 * Also allowing multiple shifts would index fshift beyond bounds.
834 for (i = DIM - 1; i >= 1; i--)
836 if (dx[i] > pbc->hbox_diag[i])
838 for (j = i; j >= 0; j--)
840 dx[j] -= pbc->box[i][j];
844 else if (dx[i] <= pbc->mhbox_diag[i])
846 for (j = i; j >= 0; j--)
848 dx[j] += pbc->box[i][j];
853 /* Allow 2 shifts in x */
854 if (dx[XX] > pbc->hbox_diag[XX])
856 dx[XX] -= pbc->fbox_diag[XX];
858 if (dx[XX] > pbc->hbox_diag[XX])
860 dx[XX] -= pbc->fbox_diag[XX];
864 else if (dx[XX] <= pbc->mhbox_diag[XX])
866 dx[XX] += pbc->fbox_diag[XX];
868 if (dx[XX] <= pbc->mhbox_diag[XX])
870 dx[XX] += pbc->fbox_diag[XX];
874 /* dx is the distance in a rectangular box */
876 if (d2min > pbc->max_cutoff2)
878 copy_rvec(dx, dx_start);
879 copy_ivec(ishift, ishift_start);
881 /* Now try all possible shifts, when the distance is within max_cutoff
882 * it must be the shortest possible distance.
885 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
887 rvec_add(dx_start, pbc->tric_vec[i], trial);
888 d2trial = norm2(trial);
891 copy_rvec(trial, dx);
892 ivec_add(ishift_start, pbc->tric_shift[i], ishift);
900 for (i = 0; i < DIM; i++)
904 if (dx[i] > pbc->hbox_diag[i])
906 dx[i] -= pbc->fbox_diag[i];
909 else if (dx[i] <= pbc->mhbox_diag[i])
911 dx[i] += pbc->fbox_diag[i];
919 for (i = DIM - 1; i >= 1; i--)
923 if (dx[i] > pbc->hbox_diag[i])
925 for (j = i; j >= 0; j--)
927 dx[j] -= pbc->box[i][j];
931 else if (dx[i] <= pbc->mhbox_diag[i])
933 for (j = i; j >= 0; j--)
935 dx[j] += pbc->box[i][j];
939 d2min += dx[i] * dx[i];
944 /* Allow 2 shifts in x */
945 if (dx[XX] > pbc->hbox_diag[XX])
947 dx[XX] -= pbc->fbox_diag[XX];
949 if (dx[XX] > pbc->hbox_diag[XX])
951 dx[XX] -= pbc->fbox_diag[XX];
955 else if (dx[XX] <= pbc->mhbox_diag[XX])
957 dx[XX] += pbc->fbox_diag[XX];
959 if (dx[XX] <= pbc->mhbox_diag[XX])
961 dx[XX] += pbc->fbox_diag[XX];
965 d2min += dx[XX] * dx[XX];
967 if (d2min > pbc->max_cutoff2)
969 copy_rvec(dx, dx_start);
970 copy_ivec(ishift, ishift_start);
971 /* Now try all possible shifts, when the distance is within max_cutoff
972 * it must be the shortest possible distance.
975 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
977 rvec_add(dx_start, pbc->tric_vec[i], trial);
979 for (j = 0; j < DIM; j++)
983 d2trial += trial[j] * trial[j];
988 copy_rvec(trial, dx);
989 ivec_add(ishift_start, pbc->tric_shift[i], ishift);
998 if (dx[i] > pbc->hbox_diag[i])
1000 dx[i] -= pbc->fbox_diag[i];
1003 else if (dx[i] <= pbc->mhbox_diag[i])
1005 dx[i] += pbc->fbox_diag[i];
1011 if (dx[i] > pbc->hbox_diag[i])
1013 rvec_dec(dx, pbc->box[i]);
1016 else if (dx[i] <= pbc->mhbox_diag[i])
1018 rvec_inc(dx, pbc->box[i]);
1022 case epbcdxSCREW_RECT:
1023 /* The shift definition requires x first */
1024 if (dx[XX] > pbc->hbox_diag[XX])
1026 dx[XX] -= pbc->fbox_diag[XX];
1029 else if (dx[XX] <= pbc->mhbox_diag[XX])
1031 dx[XX] += pbc->fbox_diag[XX];
1034 if (ishift[XX] == 1 || ishift[XX] == -1)
1036 /* Rotate around the x-axis in the middle of the box */
1037 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
1038 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
1040 /* Normal pbc for y and z */
1041 for (i = YY; i <= ZZ; i++)
1043 if (dx[i] > pbc->hbox_diag[i])
1045 dx[i] -= pbc->fbox_diag[i];
1048 else if (dx[i] <= pbc->mhbox_diag[i])
1050 dx[i] += pbc->fbox_diag[i];
1056 case epbcdxUNSUPPORTED: break;
1059 "Internal error in pbc_dx_aiuc, set_pbc_dd or set_pbc has not been called");
1062 is = IVEC2IS(ishift);
1065 range_check_mesg(is, 0, SHIFTS, "PBC shift vector index range check.");
1071 //! Compute distance vector in double precision
1072 void pbc_dx_d(const t_pbc* pbc, const dvec x1, const dvec x2, dvec dx)
1075 dvec dx_start, trial;
1076 double d2min, d2trial;
1079 dvec_sub(x1, x2, dx);
1081 switch (pbc->ePBCDX)
1083 case epbcdxRECTANGULAR:
1085 for (i = 0; i < DIM; i++)
1089 while (dx[i] > pbc->hbox_diag[i])
1091 dx[i] -= pbc->fbox_diag[i];
1093 while (dx[i] <= pbc->mhbox_diag[i])
1095 dx[i] += pbc->fbox_diag[i];
1100 case epbcdxTRICLINIC:
1103 for (i = DIM - 1; i >= 0; i--)
1107 while (dx[i] > pbc->hbox_diag[i])
1109 for (j = i; j >= 0; j--)
1111 dx[j] -= pbc->box[i][j];
1114 while (dx[i] <= pbc->mhbox_diag[i])
1116 for (j = i; j >= 0; j--)
1118 dx[j] += pbc->box[i][j];
1121 d2min += dx[i] * dx[i];
1124 if (d2min > pbc->max_cutoff2)
1126 copy_dvec(dx, dx_start);
1127 /* Now try all possible shifts, when the distance is within max_cutoff
1128 * it must be the shortest possible distance.
1131 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
1133 for (j = 0; j < DIM; j++)
1135 trial[j] = dx_start[j] + pbc->tric_vec[i][j];
1138 for (j = 0; j < DIM; j++)
1142 d2trial += trial[j] * trial[j];
1145 if (d2trial < d2min)
1147 copy_dvec(trial, dx);
1154 case epbcdxSCREW_RECT:
1155 /* The shift definition requires x first */
1157 while (dx[XX] > pbc->hbox_diag[XX])
1159 dx[XX] -= pbc->fbox_diag[XX];
1162 while (dx[XX] <= pbc->mhbox_diag[XX])
1164 dx[XX] += pbc->fbox_diag[YY];
1169 /* Rotate around the x-axis in the middle of the box */
1170 dx[YY] = pbc->box[YY][YY] - x1[YY] - x2[YY];
1171 dx[ZZ] = pbc->box[ZZ][ZZ] - x1[ZZ] - x2[ZZ];
1173 /* Normal pbc for y and z */
1174 for (i = YY; i <= ZZ; i++)
1176 while (dx[i] > pbc->hbox_diag[i])
1178 dx[i] -= pbc->fbox_diag[i];
1180 while (dx[i] <= pbc->mhbox_diag[i])
1182 dx[i] += pbc->fbox_diag[i];
1187 case epbcdxUNSUPPORTED: break;
1188 default: gmx_fatal(FARGS, "Internal error in pbc_dx, set_pbc has not been called");
1192 void calc_shifts(const matrix box, rvec shift_vec[])
1194 for (int n = 0, m = -D_BOX_Z; m <= D_BOX_Z; m++)
1196 for (int l = -D_BOX_Y; l <= D_BOX_Y; l++)
1198 for (int k = -D_BOX_X; k <= D_BOX_X; k++, n++)
1200 for (int d = 0; d < DIM; d++)
1202 shift_vec[n][d] = k * box[XX][d] + l * box[YY][d] + m * box[ZZ][d];
1209 void calc_box_center(int ecenter, const matrix box, rvec box_center)
1213 clear_rvec(box_center);
1217 for (m = 0; (m < DIM); m++)
1219 for (d = 0; d < DIM; d++)
1221 box_center[d] += 0.5 * box[m][d];
1226 for (d = 0; d < DIM; d++)
1228 box_center[d] = 0.5 * box[d][d];
1231 case ecenterZERO: break;
1232 default: gmx_fatal(FARGS, "Unsupported value %d for ecenter", ecenter);
1236 void calc_triclinic_images(const matrix box, rvec img[])
1240 /* Calculate 3 adjacent images in the xy-plane */
1241 copy_rvec(box[0], img[0]);
1242 copy_rvec(box[1], img[1]);
1245 svmul(-1, img[1], img[1]);
1247 rvec_sub(img[1], img[0], img[2]);
1249 /* Get the next 3 in the xy-plane as mirror images */
1250 for (i = 0; i < 3; i++)
1252 svmul(-1, img[i], img[3 + i]);
1255 /* Calculate the first 4 out of xy-plane images */
1256 copy_rvec(box[2], img[6]);
1259 svmul(-1, img[6], img[6]);
1261 for (i = 0; i < 3; i++)
1263 rvec_add(img[6], img[i + 1], img[7 + i]);
1266 /* Mirror the last 4 from the previous in opposite rotation */
1267 for (i = 0; i < 4; i++)
1269 svmul(-1, img[6 + (2 + i) % 4], img[10 + i]);
1273 void calc_compact_unitcell_vertices(int ecenter, const matrix box, rvec vert[])
1275 rvec img[NTRICIMG], box_center;
1276 int n, i, j, tmp[4], d;
1277 const real oneFourth = 0.25;
1279 calc_triclinic_images(box, img);
1282 for (i = 2; i <= 5; i += 3)
1293 tmp[2] = (i + 1) % 6;
1294 tmp[3] = tmp[1] + 4;
1295 for (j = 0; j < 4; j++)
1297 for (d = 0; d < DIM; d++)
1299 vert[n][d] = img[i][d] + img[tmp[j]][d] + img[tmp[(j + 1) % 4]][d];
1304 for (i = 7; i <= 13; i += 6)
1306 tmp[0] = (i - 7) / 2;
1307 tmp[1] = tmp[0] + 1;
1317 for (j = 0; j < 4; j++)
1319 for (d = 0; d < DIM; d++)
1321 vert[n][d] = img[i][d] + img[tmp[j]][d] + img[tmp[(j + 1) % 4]][d];
1326 for (i = 9; i <= 11; i += 2)
1336 tmp[1] = tmp[0] + 1;
1346 for (j = 0; j < 4; j++)
1348 for (d = 0; d < DIM; d++)
1350 vert[n][d] = img[i][d] + img[tmp[j]][d] + img[tmp[(j + 1) % 4]][d];
1356 calc_box_center(ecenter, box, box_center);
1357 for (i = 0; i < NCUCVERT; i++)
1359 for (d = 0; d < DIM; d++)
1361 vert[i][d] = vert[i][d] * oneFourth + box_center[d];
1366 int* compact_unitcell_edges()
1368 /* this is an index in vert[] (see calc_box_vertices) */
1369 /*static int edge[NCUCEDGE*2];*/
1371 static const int hexcon[24] = { 0, 9, 1, 19, 2, 15, 3, 21, 4, 17, 5, 11,
1372 6, 23, 7, 13, 8, 20, 10, 18, 12, 16, 14, 22 };
1375 snew(edge, NCUCEDGE * 2);
1378 for (i = 0; i < 6; i++)
1380 for (j = 0; j < 4; j++)
1382 edge[e++] = 4 * i + j;
1383 edge[e++] = 4 * i + (j + 1) % 4;
1386 for (i = 0; i < 12 * 2; i++)
1388 edge[e++] = hexcon[i];
1394 void put_atoms_in_box(int ePBC, const matrix box, gmx::ArrayRef<gmx::RVec> x)
1398 if (ePBC == epbcSCREW)
1400 gmx_fatal(FARGS, "Sorry, %s pbc is not yet supported", epbc_names[ePBC]);
1414 for (gmx::index i = 0; (i < x.ssize()); ++i)
1416 for (m = npbcdim - 1; m >= 0; m--)
1420 for (d = 0; d <= m; d++)
1422 x[i][d] += box[m][d];
1425 while (x[i][m] >= box[m][m])
1427 for (d = 0; d <= m; d++)
1429 x[i][d] -= box[m][d];
1437 for (gmx::index i = 0; (i < x.ssize()); ++i)
1439 for (d = 0; d < npbcdim; d++)
1443 x[i][d] += box[d][d];
1445 while (x[i][d] >= box[d][d])
1447 x[i][d] -= box[d][d];
1454 void put_atoms_in_box_omp(int ePBC, const matrix box, gmx::ArrayRef<gmx::RVec> x, gmx_unused int nth)
1456 #pragma omp parallel for num_threads(nth) schedule(static)
1457 for (int t = 0; t < nth; t++)
1461 size_t natoms = x.size();
1462 size_t offset = (natoms * t) / nth;
1463 size_t len = (natoms * (t + 1)) / nth - offset;
1464 put_atoms_in_box(ePBC, box, x.subArray(offset, len));
1466 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
1470 void put_atoms_in_triclinic_unitcell(int ecenter, const matrix box, gmx::ArrayRef<gmx::RVec> x)
1472 rvec box_center, shift_center;
1473 real shm01, shm02, shm12, shift;
1476 calc_box_center(ecenter, box, box_center);
1478 /* The product of matrix shm with a coordinate gives the shift vector
1479 which is required determine the periodic cell position */
1480 shm01 = box[1][0] / box[1][1];
1481 shm02 = (box[1][1] * box[2][0] - box[2][1] * box[1][0]) / (box[1][1] * box[2][2]);
1482 shm12 = box[2][1] / box[2][2];
1484 clear_rvec(shift_center);
1485 for (d = 0; d < DIM; d++)
1487 rvec_inc(shift_center, box[d]);
1489 svmul(0.5, shift_center, shift_center);
1490 rvec_sub(box_center, shift_center, shift_center);
1492 shift_center[0] = shm01 * shift_center[1] + shm02 * shift_center[2];
1493 shift_center[1] = shm12 * shift_center[2];
1494 shift_center[2] = 0;
1496 for (gmx::index i = 0; (i < x.ssize()); ++i)
1498 for (m = DIM - 1; m >= 0; m--)
1500 shift = shift_center[m];
1503 shift += shm01 * x[i][1] + shm02 * x[i][2];
1507 shift += shm12 * x[i][2];
1509 while (x[i][m] - shift < 0)
1511 for (d = 0; d <= m; d++)
1513 x[i][d] += box[m][d];
1516 while (x[i][m] - shift >= box[m][m])
1518 for (d = 0; d <= m; d++)
1520 x[i][d] -= box[m][d];
1527 void put_atoms_in_compact_unitcell(int ePBC, int ecenter, const matrix box, gmx::ArrayRef<gmx::RVec> x)
1530 rvec box_center, dx;
1532 set_pbc(&pbc, ePBC, box);
1534 if (pbc.ePBCDX == epbcdxUNSUPPORTED)
1536 gmx_fatal(FARGS, "Can not put atoms in compact unitcell with unsupported PBC");
1539 calc_box_center(ecenter, box, box_center);
1540 for (gmx::index i = 0; (i < x.ssize()); ++i)
1542 pbc_dx(&pbc, x[i], box_center, dx);
1543 rvec_add(box_center, dx, x[i]);
1547 /*! \brief Make molecules whole by shifting positions
1549 * \param[in] fplog Log file
1550 * \param[in] ePBC The PBC type
1551 * \param[in] box The simulation box
1552 * \param[in] mtop System topology definition
1553 * \param[in,out] x The coordinates of the atoms
1554 * \param[in] bFirst Specifier for first-time PBC removal
1556 static void low_do_pbc_mtop(FILE* fplog, int ePBC, const matrix box, const gmx_mtop_t* mtop, rvec x[], gmx_bool bFirst)
1561 if (bFirst && fplog)
1563 fprintf(fplog, "Removing pbc first time\n");
1568 for (const gmx_molblock_t& molb : mtop->molblock)
1570 const gmx_moltype_t& moltype = mtop->moltype[molb.type];
1571 if (moltype.atoms.nr == 1 || (!bFirst && moltype.atoms.nr == 1))
1573 /* Just one atom or charge group in the molecule, no PBC required */
1574 as += molb.nmol * moltype.atoms.nr;
1578 mk_graph_moltype(moltype, graph);
1580 for (mol = 0; mol < molb.nmol; mol++)
1582 mk_mshift(fplog, graph, ePBC, box, x + as);
1584 shift_self(graph, box, x + as);
1585 /* The molecule is whole now.
1586 * We don't need the second mk_mshift call as in do_pbc_first,
1587 * since we no longer need this graph.
1590 as += moltype.atoms.nr;
1598 void do_pbc_first_mtop(FILE* fplog, int ePBC, const matrix box, const gmx_mtop_t* mtop, rvec x[])
1600 low_do_pbc_mtop(fplog, ePBC, box, mtop, x, TRUE);
1603 void do_pbc_mtop(int ePBC, const matrix box, const gmx_mtop_t* mtop, rvec x[])
1605 low_do_pbc_mtop(nullptr, ePBC, box, mtop, x, FALSE);