Add SIMD version of pbc_dx_aiuc
[gromacs.git] / src / gromacs / pbcutil / pbc.cpp
blobe5078b821859e740a4d701a18b9030fb6a55a631
1 /*
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.
37 /*! \internal \file
38 * \brief
39 * Implements routines in pbc.h.
41 * Utility functions for handling periodic boundary conditions.
42 * Mainly used in analysis tools.
44 #include "gmxpre.h"
46 #include "pbc.h"
48 #include <cmath>
50 #include <algorithm>
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. */
71 enum {
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)
86 int npbcdim = 0;
88 switch (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);
97 return npbcdim;
100 int inputrec2nboundeddim(const t_inputrec *ir)
102 if (ir->nwall == 2 && ir->ePBC == epbcXY)
104 return 3;
106 else
108 return ePBC2npbcdim(ir->ePBC);
112 void dump_pbc(FILE *fp, t_pbc *pbc)
114 rvec sum_box;
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)
134 const char *ptr;
136 if (ePBC == -1)
138 ePBC = guess_ePBC(box);
141 if (ePBC == epbcNONE)
143 return NULL;
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] ||
155 (ePBC != epbcXY &&
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.";
161 else
163 ptr = NULL;
166 return ptr;
169 void matrix_convert(matrix box, const rvec vec, const rvec angleInDegrees)
171 rvec angle;
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]));
192 if (ePBC != epbcXY)
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.
202 if (ePBC == epbcXY)
204 min_ss = std::min(box[XX][XX], box[YY][YY]);
206 else
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)
219 int ePBC;
221 if (box[XX][XX] > 0 && box[YY][YY] > 0 && box[ZZ][ZZ] > 0)
223 ePBC = epbcXYZ;
225 else if (box[XX][XX] > 0 && box[YY][YY] > 0 && box[ZZ][ZZ] == 0)
227 ePBC = epbcXY;
229 else if (box[XX][XX] == 0 && box[YY][YY] == 0 && box[ZZ][ZZ] == 0)
231 ePBC = epbcNONE;
233 else
235 if (!bWarnedGuess)
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]);
240 bWarnedGuess = TRUE;
242 ePBC = epbcNONE;
245 if (debug)
247 fprintf(debug, "Guessed pbc = %s from the box matrix\n", epbc_names[ePBC]);
250 return 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;
258 shift = 0;
260 /* correct elem d of vector v with vector d */
261 while (box[v][d] > BOX_MARGIN_CORRECT*0.5*box[d][d])
263 if (fplog)
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]);
269 shift--;
270 if (fplog)
272 pr_rvecs(fplog, 0, "new box", box, DIM);
274 if (shift <= -maxshift)
276 gmx_fatal(FARGS,
277 "Box was shifted at least %d times. Please see log-file.",
278 maxshift);
281 while (box[v][d] < -BOX_MARGIN_CORRECT*0.5*box[d][d])
283 if (fplog)
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]);
289 shift++;
290 if (fplog)
292 pr_rvecs(fplog, 0, "new box", box, DIM);
294 if (shift >= maxshift)
296 gmx_fatal(FARGS,
297 "Box was shifted at least %d times. Please see log-file.",
298 maxshift);
302 return shift;
305 gmx_bool correct_box(FILE *fplog, int step, tensor box, t_graph *graph)
307 int zy, zx, yx, i;
308 gmx_bool bCorrected;
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;
327 return bCorrected;
330 int ndof_com(t_inputrec *ir)
332 int n = 0;
334 switch (ir->ePBC)
336 case epbcXYZ:
337 case epbcNONE:
338 n = 3;
339 break;
340 case epbcXY:
341 n = (ir->nwall == 0 ? 3 : 2);
342 break;
343 case epbcSCREW:
344 n = 1;
345 break;
346 default:
347 gmx_incons("Unknown pbc in calc_nrdf");
350 return n;
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 };
358 ivec bPBC;
359 const char *ptr;
361 pbc->ePBC = ePBC;
362 pbc->ndim_ePBC = ePBC2npbcdim(ePBC);
364 if (pbc->ePBC == epbcNONE)
366 pbc->ePBCDX = epbcdxNOPBC;
368 return;
371 copy_mat(box, pbc->box);
372 pbc->max_cutoff2 = 0;
373 pbc->dim = -1;
374 pbc->ntric_vec = 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);
384 if (ptr)
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;
391 else
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");
399 int npbcdim = 0;
400 for (int i = 0; i < DIM; i++)
402 if ((dd_pbc && dd_pbc[i] == 0) || (ePBC == epbcXY && i == ZZ))
404 bPBC[i] = 0;
406 else
408 bPBC[i] = 1;
409 npbcdim++;
412 switch (npbcdim)
414 case 1:
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++)
421 if (bPBC[i])
423 pbc->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;
434 break;
435 case 2:
436 pbc->ePBCDX = epbcdx2D_RECT;
437 for (int i = 0; i < DIM; i++)
439 if (!bPBC[i])
441 pbc->dim = i;
444 for (int i = 0; i < DIM; i++)
446 if (bPBC[i])
448 for (int j = 0; j < i; j++)
450 if (pbc->box[i][j] != 0)
452 pbc->ePBCDX = epbcdx2D_TRIC;
457 break;
458 case 3:
459 if (ePBC != epbcSCREW)
461 if (TRICLINIC(box))
463 pbc->ePBCDX = epbcdxTRICLINIC;
465 else
467 pbc->ePBCDX = epbcdxRECTANGULAR;
470 else
472 pbc->ePBCDX = (box[ZZ][YY] == 0 ? epbcdxSCREW_RECT : epbcdxSCREW_TRIC);
473 if (pbc->ePBCDX == epbcdxSCREW_TRIC)
475 fprintf(stderr,
476 "Screw pbc is not yet implemented for triclinic boxes.\n"
477 "Can not fix pbc.\n");
478 pbc->ePBCDX = epbcdxUNSUPPORTED;
481 break;
482 default:
483 gmx_fatal(FARGS, "Incorrect number of pbc dimensions with DD: %d",
484 npbcdim);
486 pbc->max_cutoff2 = max_cutoff2(ePBC, box);
488 if (pbc->ePBCDX == epbcdxTRICLINIC ||
489 pbc->ePBCDX == epbcdx2D_TRIC ||
490 pbc->ePBCDX == epbcdxSCREW_TRIC)
492 if (debug)
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++)
500 int k = order[kk];
501 if (!bPBC[ZZ] && k != 0)
503 continue;
505 for (int jj = 0; jj < 3; jj++)
507 int j = order[jj];
508 if (!bPBC[YY] && j != 0)
510 continue;
512 for (int ii = 0; ii < 3; ii++)
514 int i = order[ii];
515 if (!bPBC[XX] && i != 0)
517 continue;
519 /* A shift is only useful when it is trilinic */
520 if (j != 0 || k != 0)
522 rvec trial;
523 rvec pos;
524 real d2old = 0;
525 real d2new = 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.
533 if (d == pbc->dim)
535 trial[d] = 0;
536 pos[d] = 0;
538 else
540 if (trial[d] < 0)
542 pos[d] = std::min( pbc->hbox_diag[d], -trial[d]);
544 else
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));
559 if (shift)
561 real d2new_c = 0;
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)
568 bUse = FALSE;
572 if (bUse)
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);
581 else
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;
587 pbc->ntric_vec++;
589 if (debug)
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)
610 if (ePBC == -1)
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)
624 pbc->ePBC = ePBC;
626 return NULL;
629 if (nullptr == domdecCells)
631 low_set_pbc(pbc, ePBC, NULL, box);
633 else
635 if (ePBC == epbcSCREW && domdecCells[XX] > 1)
637 /* The rotation has been taken care of during coordinate communication */
638 ePBC = epbcXYZ;
641 ivec usePBC;
642 int npbcdim = 0;
643 for (int i = 0; i < DIM; i++)
645 usePBC[i] = 0;
646 if (domdecCells[i] <= (bSingleDir ? 1 : 2) &&
647 !(ePBC == epbcXY && i == ZZ))
649 usePBC[i] = 1;
650 npbcdim++;
654 if (npbcdim > 0)
656 low_set_pbc(pbc, ePBC, usePBC, box);
658 else
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)
669 int i, j;
670 rvec dx_start, trial;
671 real d2min, d2trial;
672 gmx_bool bRot;
674 rvec_sub(x1, x2, dx);
676 switch (pbc->ePBCDX)
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];
690 break;
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 */
710 d2min = norm2(dx);
711 if (d2min > pbc->max_cutoff2)
713 copy_rvec(dx, dx_start);
714 d2min = norm2(dx);
715 /* Now try all possible shifts, when the distance is within max_cutoff
716 * it must be the shortest possible distance.
718 i = 0;
719 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
721 rvec_add(dx_start, pbc->tric_vec[i], trial);
722 d2trial = norm2(trial);
723 if (d2trial < d2min)
725 copy_rvec(trial, dx);
726 d2min = d2trial;
728 i++;
731 break;
732 case epbcdx2D_RECT:
733 for (i = 0; i < DIM; i++)
735 if (i != pbc->dim)
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];
747 break;
748 case epbcdx2D_TRIC:
749 d2min = 0;
750 for (i = DIM-1; i >= 0; i--)
752 if (i != pbc->dim)
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);
774 d2min = norm2(dx);
775 /* Now try all possible shifts, when the distance is within max_cutoff
776 * it must be the shortest possible distance.
778 i = 0;
779 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
781 rvec_add(dx_start, pbc->tric_vec[i], trial);
782 d2trial = 0;
783 for (j = 0; j < DIM; j++)
785 if (j != pbc->dim)
787 d2trial += trial[j]*trial[j];
790 if (d2trial < d2min)
792 copy_rvec(trial, dx);
793 d2min = d2trial;
795 i++;
798 break;
799 case epbcdxSCREW_RECT:
800 /* The shift definition requires x first */
801 bRot = FALSE;
802 while (dx[XX] > pbc->hbox_diag[XX])
804 dx[XX] -= pbc->fbox_diag[XX];
805 bRot = !bRot;
807 while (dx[XX] <= pbc->mhbox_diag[XX])
809 dx[XX] += pbc->fbox_diag[YY];
810 bRot = !bRot;
812 if (bRot)
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];
830 break;
831 case epbcdxNOPBC:
832 case epbcdxUNSUPPORTED:
833 break;
834 default:
835 gmx_fatal(FARGS, "Internal error in pbc_dx, set_pbc has not been called");
836 break;
840 int pbc_dx_aiuc(const t_pbc *pbc, const rvec x1, const rvec x2, rvec dx)
842 int i, j, is;
843 rvec dx_start, trial;
844 real d2min, d2trial;
845 ivec ishift, ishift_start;
847 rvec_sub(x1, x2, dx);
848 clear_ivec(ishift);
850 switch (pbc->ePBCDX)
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];
858 ishift[i]--;
860 else if (dx[i] <= pbc->mhbox_diag[i])
862 dx[i] += pbc->fbox_diag[i];
863 ishift[i]++;
866 break;
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];
883 ishift[i]--;
885 else if (dx[i] <= pbc->mhbox_diag[i])
887 for (j = i; j >= 0; j--)
889 dx[j] += pbc->box[i][j];
891 ishift[i]++;
894 /* Allow 2 shifts in x */
895 if (dx[XX] > pbc->hbox_diag[XX])
897 dx[XX] -= pbc->fbox_diag[XX];
898 ishift[XX]--;
899 if (dx[XX] > pbc->hbox_diag[XX])
901 dx[XX] -= pbc->fbox_diag[XX];
902 ishift[XX]--;
905 else if (dx[XX] <= pbc->mhbox_diag[XX])
907 dx[XX] += pbc->fbox_diag[XX];
908 ishift[XX]++;
909 if (dx[XX] <= pbc->mhbox_diag[XX])
911 dx[XX] += pbc->fbox_diag[XX];
912 ishift[XX]++;
915 /* dx is the distance in a rectangular box */
916 d2min = norm2(dx);
917 if (d2min > pbc->max_cutoff2)
919 copy_rvec(dx, dx_start);
920 copy_ivec(ishift, ishift_start);
921 d2min = norm2(dx);
922 /* Now try all possible shifts, when the distance is within max_cutoff
923 * it must be the shortest possible distance.
925 i = 0;
926 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
928 rvec_add(dx_start, pbc->tric_vec[i], trial);
929 d2trial = norm2(trial);
930 if (d2trial < d2min)
932 copy_rvec(trial, dx);
933 ivec_add(ishift_start, pbc->tric_shift[i], ishift);
934 d2min = d2trial;
936 i++;
939 break;
940 case epbcdx2D_RECT:
941 for (i = 0; i < DIM; i++)
943 if (i != pbc->dim)
945 if (dx[i] > pbc->hbox_diag[i])
947 dx[i] -= pbc->fbox_diag[i];
948 ishift[i]--;
950 else if (dx[i] <= pbc->mhbox_diag[i])
952 dx[i] += pbc->fbox_diag[i];
953 ishift[i]++;
957 break;
958 case epbcdx2D_TRIC:
959 d2min = 0;
960 for (i = DIM-1; i >= 1; i--)
962 if (i != pbc->dim)
964 if (dx[i] > pbc->hbox_diag[i])
966 for (j = i; j >= 0; j--)
968 dx[j] -= pbc->box[i][j];
970 ishift[i]--;
972 else if (dx[i] <= pbc->mhbox_diag[i])
974 for (j = i; j >= 0; j--)
976 dx[j] += pbc->box[i][j];
978 ishift[i]++;
980 d2min += dx[i]*dx[i];
983 if (pbc->dim != XX)
985 /* Allow 2 shifts in x */
986 if (dx[XX] > pbc->hbox_diag[XX])
988 dx[XX] -= pbc->fbox_diag[XX];
989 ishift[XX]--;
990 if (dx[XX] > pbc->hbox_diag[XX])
992 dx[XX] -= pbc->fbox_diag[XX];
993 ishift[XX]--;
996 else if (dx[XX] <= pbc->mhbox_diag[XX])
998 dx[XX] += pbc->fbox_diag[XX];
999 ishift[XX]++;
1000 if (dx[XX] <= pbc->mhbox_diag[XX])
1002 dx[XX] += pbc->fbox_diag[XX];
1003 ishift[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.
1015 i = 0;
1016 while ((d2min > pbc->max_cutoff2) && (i < pbc->ntric_vec))
1018 rvec_add(dx_start, pbc->tric_vec[i], trial);
1019 d2trial = 0;
1020 for (j = 0; j < DIM; j++)
1022 if (j != pbc->dim)
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);
1031 d2min = d2trial;
1033 i++;
1036 break;
1037 case epbcdx1D_RECT:
1038 i = pbc->dim;
1039 if (dx[i] > pbc->hbox_diag[i])
1041 dx[i] -= pbc->fbox_diag[i];
1042 ishift[i]--;
1044 else if (dx[i] <= pbc->mhbox_diag[i])
1046 dx[i] += pbc->fbox_diag[i];
1047 ishift[i]++;
1049 break;
1050 case epbcdx1D_TRIC:
1051 i = pbc->dim;
1052 if (dx[i] > pbc->hbox_diag[i])
1054 rvec_dec(dx, pbc->box[i]);
1055 ishift[i]--;
1057 else if (dx[i] <= pbc->mhbox_diag[i])
1059 rvec_inc(dx, pbc->box[i]);
1060 ishift[i]++;
1062 break;
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];
1068 ishift[XX]--;
1070 else if (dx[XX] <= pbc->mhbox_diag[XX])
1072 dx[XX] += pbc->fbox_diag[XX];
1073 ishift[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];
1087 ishift[i]--;
1089 else if (dx[i] <= pbc->mhbox_diag[i])
1091 dx[i] += pbc->fbox_diag[i];
1092 ishift[i]++;
1095 break;
1096 case epbcdxNOPBC:
1097 case epbcdxUNSUPPORTED:
1098 break;
1099 default:
1100 gmx_fatal(FARGS, "Internal error in pbc_dx_aiuc, set_pbc_dd or set_pbc has not been called");
1101 break;
1104 is = IVEC2IS(ishift);
1105 if (debug)
1107 range_check_mesg(is, 0, SHIFTS, "PBC shift vector index range check.");
1110 return is;
1113 //! Compute distance vector in double precision
1114 void pbc_dx_d(const t_pbc *pbc, const dvec x1, const dvec x2, dvec dx)
1116 int i, j;
1117 dvec dx_start, trial;
1118 double d2min, d2trial;
1119 gmx_bool bRot;
1121 dvec_sub(x1, x2, dx);
1123 switch (pbc->ePBCDX)
1125 case epbcdxRECTANGULAR:
1126 case epbcdx2D_RECT:
1127 for (i = 0; i < DIM; i++)
1129 if (i != pbc->dim)
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];
1141 break;
1142 case epbcdxTRICLINIC:
1143 case epbcdx2D_TRIC:
1144 d2min = 0;
1145 for (i = DIM-1; i >= 0; i--)
1147 if (i != pbc->dim)
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.
1172 i = 0;
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];
1179 d2trial = 0;
1180 for (j = 0; j < DIM; j++)
1182 if (j != pbc->dim)
1184 d2trial += trial[j]*trial[j];
1187 if (d2trial < d2min)
1189 copy_dvec(trial, dx);
1190 d2min = d2trial;
1192 i++;
1195 break;
1196 case epbcdxSCREW_RECT:
1197 /* The shift definition requires x first */
1198 bRot = FALSE;
1199 while (dx[XX] > pbc->hbox_diag[XX])
1201 dx[XX] -= pbc->fbox_diag[XX];
1202 bRot = !bRot;
1204 while (dx[XX] <= pbc->mhbox_diag[XX])
1206 dx[XX] += pbc->fbox_diag[YY];
1207 bRot = !bRot;
1209 if (bRot)
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];
1227 break;
1228 case epbcdxNOPBC:
1229 case epbcdxUNSUPPORTED:
1230 break;
1231 default:
1232 gmx_fatal(FARGS, "Internal error in pbc_dx, set_pbc has not been called");
1233 break;
1237 //! Compute the box image corresponding to input vectors
1238 gmx_bool image_rect(ivec xi, ivec xj, ivec box_size, real rlong2, int *shift, real *r2)
1240 int m, t;
1241 int dx, b, b_2;
1242 real dxr, rij2;
1244 rij2 = 0.0;
1245 t = 0;
1246 for (m = 0; (m < DIM); m++)
1248 dx = xi[m]-xj[m];
1249 t *= DIM;
1250 b = box_size[m];
1251 b_2 = b/2;
1252 if (dx < -b_2)
1254 t += 2;
1255 dx += b;
1257 else if (dx > b_2)
1259 dx -= b;
1261 else
1263 t += 1;
1265 dxr = dx;
1266 rij2 += dxr*dxr;
1267 if (rij2 >= rlong2)
1269 return FALSE;
1273 *shift = t;
1274 *r2 = rij2;
1275 return TRUE;
1278 gmx_bool image_cylindric(ivec xi, ivec xj, ivec box_size, real rlong2,
1279 int *shift, real *r2)
1281 int m, t;
1282 int dx, b, b_2;
1283 real dxr, rij2;
1285 rij2 = 0.0;
1286 t = 0;
1287 for (m = 0; (m < DIM); m++)
1289 dx = xi[m]-xj[m];
1290 t *= DIM;
1291 b = box_size[m];
1292 b_2 = b/2;
1293 if (dx < -b_2)
1295 t += 2;
1296 dx += b;
1298 else if (dx > b_2)
1300 dx -= b;
1302 else
1304 t += 1;
1307 dxr = dx;
1308 rij2 += dxr*dxr;
1309 if (m < ZZ)
1311 if (rij2 >= rlong2)
1313 return FALSE;
1318 *shift = t;
1319 *r2 = rij2;
1320 return TRUE;
1323 void calc_shifts(const matrix box, rvec shift_vec[])
1325 int k, l, m, d, n, test;
1327 n = 0;
1328 for (m = -D_BOX_Z; m <= D_BOX_Z; m++)
1330 for (l = -D_BOX_Y; l <= D_BOX_Y; l++)
1332 for (k = -D_BOX_X; k <= D_BOX_X; k++, n++)
1334 test = XYZ2IS(k, l, m);
1335 if (n != test)
1337 gmx_incons("inconsistent shift numbering");
1339 for (d = 0; d < DIM; d++)
1341 shift_vec[n][d] = k*box[XX][d] + l*box[YY][d] + m*box[ZZ][d];
1348 void calc_box_center(int ecenter, const matrix box, rvec box_center)
1350 int d, m;
1352 clear_rvec(box_center);
1353 switch (ecenter)
1355 case ecenterTRIC:
1356 for (m = 0; (m < DIM); m++)
1358 for (d = 0; d < DIM; d++)
1360 box_center[d] += 0.5*box[m][d];
1363 break;
1364 case ecenterRECT:
1365 for (d = 0; d < DIM; d++)
1367 box_center[d] = 0.5*box[d][d];
1369 break;
1370 case ecenterZERO:
1371 break;
1372 default:
1373 gmx_fatal(FARGS, "Unsupported value %d for ecenter", ecenter);
1377 void calc_triclinic_images(const matrix box, rvec img[])
1379 int i;
1381 /* Calculate 3 adjacent images in the xy-plane */
1382 copy_rvec(box[0], img[0]);
1383 copy_rvec(box[1], img[1]);
1384 if (img[1][XX] < 0)
1386 svmul(-1, img[1], img[1]);
1388 rvec_sub(img[1], img[0], img[2]);
1390 /* Get the next 3 in the xy-plane as mirror images */
1391 for (i = 0; i < 3; i++)
1393 svmul(-1, img[i], img[3+i]);
1396 /* Calculate the first 4 out of xy-plane images */
1397 copy_rvec(box[2], img[6]);
1398 if (img[6][XX] < 0)
1400 svmul(-1, img[6], img[6]);
1402 for (i = 0; i < 3; i++)
1404 rvec_add(img[6], img[i+1], img[7+i]);
1407 /* Mirror the last 4 from the previous in opposite rotation */
1408 for (i = 0; i < 4; i++)
1410 svmul(-1, img[6 + (2+i) % 4], img[10+i]);
1414 void calc_compact_unitcell_vertices(int ecenter, const matrix box, rvec vert[])
1416 rvec img[NTRICIMG], box_center;
1417 int n, i, j, tmp[4], d;
1418 const real oneFourth = 0.25;
1420 calc_triclinic_images(box, img);
1422 n = 0;
1423 for (i = 2; i <= 5; i += 3)
1425 tmp[0] = i-1;
1426 if (i == 2)
1428 tmp[1] = 8;
1430 else
1432 tmp[1] = 6;
1434 tmp[2] = (i+1) % 6;
1435 tmp[3] = tmp[1]+4;
1436 for (j = 0; j < 4; j++)
1438 for (d = 0; d < DIM; d++)
1440 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1442 n++;
1445 for (i = 7; i <= 13; i += 6)
1447 tmp[0] = (i-7)/2;
1448 tmp[1] = tmp[0]+1;
1449 if (i == 7)
1451 tmp[2] = 8;
1453 else
1455 tmp[2] = 10;
1457 tmp[3] = i-1;
1458 for (j = 0; j < 4; j++)
1460 for (d = 0; d < DIM; d++)
1462 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1464 n++;
1467 for (i = 9; i <= 11; i += 2)
1469 if (i == 9)
1471 tmp[0] = 3;
1473 else
1475 tmp[0] = 0;
1477 tmp[1] = tmp[0]+1;
1478 if (i == 9)
1480 tmp[2] = 6;
1482 else
1484 tmp[2] = 12;
1486 tmp[3] = i-1;
1487 for (j = 0; j < 4; j++)
1489 for (d = 0; d < DIM; d++)
1491 vert[n][d] = img[i][d]+img[tmp[j]][d]+img[tmp[(j+1)%4]][d];
1493 n++;
1497 calc_box_center(ecenter, box, box_center);
1498 for (i = 0; i < NCUCVERT; i++)
1500 for (d = 0; d < DIM; d++)
1502 vert[i][d] = vert[i][d]*oneFourth+box_center[d];
1507 int *compact_unitcell_edges()
1509 /* this is an index in vert[] (see calc_box_vertices) */
1510 /*static int edge[NCUCEDGE*2];*/
1511 int *edge;
1512 static const int hexcon[24] = {
1513 0, 9, 1, 19, 2, 15, 3, 21,
1514 4, 17, 5, 11, 6, 23, 7, 13,
1515 8, 20, 10, 18, 12, 16, 14, 22
1517 int e, i, j;
1519 snew(edge, NCUCEDGE*2);
1521 e = 0;
1522 for (i = 0; i < 6; i++)
1524 for (j = 0; j < 4; j++)
1526 edge[e++] = 4*i + j;
1527 edge[e++] = 4*i + (j+1) % 4;
1530 for (i = 0; i < 12*2; i++)
1532 edge[e++] = hexcon[i];
1535 return edge;
1538 void put_atoms_in_box(int ePBC, const matrix box, int natoms, rvec x[])
1540 int npbcdim, i, m, d;
1542 if (ePBC == epbcSCREW)
1544 gmx_fatal(FARGS, "Sorry, %s pbc is not yet supported", epbc_names[ePBC]);
1547 if (ePBC == epbcXY)
1549 npbcdim = 2;
1551 else
1553 npbcdim = 3;
1556 if (TRICLINIC(box))
1558 for (i = 0; (i < natoms); i++)
1560 for (m = npbcdim-1; m >= 0; m--)
1562 while (x[i][m] < 0)
1564 for (d = 0; d <= m; d++)
1566 x[i][d] += box[m][d];
1569 while (x[i][m] >= box[m][m])
1571 for (d = 0; d <= m; d++)
1573 x[i][d] -= box[m][d];
1579 else
1581 for (i = 0; i < natoms; i++)
1583 for (d = 0; d < npbcdim; d++)
1585 while (x[i][d] < 0)
1587 x[i][d] += box[d][d];
1589 while (x[i][d] >= box[d][d])
1591 x[i][d] -= box[d][d];
1598 void put_atoms_in_triclinic_unitcell(int ecenter, const matrix box,
1599 int natoms, rvec x[])
1601 rvec box_center, shift_center;
1602 real shm01, shm02, shm12, shift;
1603 int i, m, d;
1605 calc_box_center(ecenter, box, box_center);
1607 /* The product of matrix shm with a coordinate gives the shift vector
1608 which is required determine the periodic cell position */
1609 shm01 = box[1][0]/box[1][1];
1610 shm02 = (box[1][1]*box[2][0] - box[2][1]*box[1][0])/(box[1][1]*box[2][2]);
1611 shm12 = box[2][1]/box[2][2];
1613 clear_rvec(shift_center);
1614 for (d = 0; d < DIM; d++)
1616 rvec_inc(shift_center, box[d]);
1618 svmul(0.5, shift_center, shift_center);
1619 rvec_sub(box_center, shift_center, shift_center);
1621 shift_center[0] = shm01*shift_center[1] + shm02*shift_center[2];
1622 shift_center[1] = shm12*shift_center[2];
1623 shift_center[2] = 0;
1625 for (i = 0; (i < natoms); i++)
1627 for (m = DIM-1; m >= 0; m--)
1629 shift = shift_center[m];
1630 if (m == 0)
1632 shift += shm01*x[i][1] + shm02*x[i][2];
1634 else if (m == 1)
1636 shift += shm12*x[i][2];
1638 while (x[i][m]-shift < 0)
1640 for (d = 0; d <= m; d++)
1642 x[i][d] += box[m][d];
1645 while (x[i][m]-shift >= box[m][m])
1647 for (d = 0; d <= m; d++)
1649 x[i][d] -= box[m][d];
1656 void put_atoms_in_compact_unitcell(int ePBC, int ecenter, const matrix box,
1657 int natoms, rvec x[])
1659 t_pbc pbc;
1660 rvec box_center, dx;
1661 int i;
1663 set_pbc(&pbc, ePBC, box);
1665 if (pbc.ePBCDX == epbcdxUNSUPPORTED)
1667 gmx_fatal(FARGS, "Can not put atoms in compact unitcell with unsupported PBC");
1670 calc_box_center(ecenter, box, box_center);
1671 for (i = 0; i < natoms; i++)
1673 pbc_dx(&pbc, x[i], box_center, dx);
1674 rvec_add(box_center, dx, x[i]);