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 //! 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
)
1246 for (m
= 0; (m
< DIM
); m
++)
1278 gmx_bool
image_cylindric(ivec xi
, ivec xj
, ivec box_size
, real rlong2
,
1279 int *shift
, real
*r2
)
1287 for (m
= 0; (m
< DIM
); m
++)
1323 void calc_shifts(const matrix box
, rvec shift_vec
[])
1325 int k
, l
, m
, d
, n
, test
;
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
);
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
)
1352 clear_rvec(box_center
);
1356 for (m
= 0; (m
< DIM
); m
++)
1358 for (d
= 0; d
< DIM
; d
++)
1360 box_center
[d
] += 0.5*box
[m
][d
];
1365 for (d
= 0; d
< DIM
; d
++)
1367 box_center
[d
] = 0.5*box
[d
][d
];
1373 gmx_fatal(FARGS
, "Unsupported value %d for ecenter", ecenter
);
1377 void calc_triclinic_images(const matrix box
, rvec img
[])
1381 /* Calculate 3 adjacent images in the xy-plane */
1382 copy_rvec(box
[0], img
[0]);
1383 copy_rvec(box
[1], img
[1]);
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]);
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
);
1423 for (i
= 2; i
<= 5; i
+= 3)
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
];
1445 for (i
= 7; i
<= 13; i
+= 6)
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
];
1467 for (i
= 9; i
<= 11; i
+= 2)
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
];
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];*/
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
1519 snew(edge
, NCUCEDGE
*2);
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
];
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
]);
1558 for (i
= 0; (i
< natoms
); i
++)
1560 for (m
= npbcdim
-1; m
>= 0; m
--)
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
];
1581 for (i
= 0; i
< natoms
; i
++)
1583 for (d
= 0; d
< npbcdim
; d
++)
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
;
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
];
1632 shift
+= shm01
*x
[i
][1] + shm02
*x
[i
][2];
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
[])
1660 rvec box_center
, dx
;
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
]);