Introduce SimulatorBuilder
[gromacs.git] / src / gromacs / pbcutil / mshift.cpp
blob1c5be20466d80244be9b2606cfbcc66b3275c631
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,2017,2018, 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 #include "gmxpre.h"
39 #include "mshift.h"
41 #include <cstring>
43 #include <algorithm>
45 #include "gromacs/math/vec.h"
46 #include "gromacs/pbcutil/pbc.h"
47 #include "gromacs/topology/idef.h"
48 #include "gromacs/topology/ifunc.h"
49 #include "gromacs/topology/topology.h"
50 #include "gromacs/utility/fatalerror.h"
51 #include "gromacs/utility/smalloc.h"
52 #include "gromacs/utility/strconvert.h"
53 #include "gromacs/utility/stringutil.h"
55 /************************************************************
57 * S H I F T U T I L I T I E S
59 ************************************************************/
62 /************************************************************
64 * G R A P H G E N E R A T I O N C O D E
66 ************************************************************/
68 static void add_gbond(t_graph *g, int a0, int a1)
70 int i;
71 int inda0, inda1;
72 gmx_bool bFound;
74 inda0 = a0 - g->at_start;
75 inda1 = a1 - g->at_start;
76 bFound = FALSE;
77 /* Search for a direct edge between a0 and a1.
78 * All egdes are bidirectional, so we only need to search one way.
80 for (i = 0; (i < g->nedge[inda0] && !bFound); i++)
82 bFound = (g->edge[inda0][i] == a1);
85 if (!bFound)
87 g->edge[inda0][g->nedge[inda0]++] = a1;
88 g->edge[inda1][g->nedge[inda1]++] = a0;
92 /* Make the actual graph for an ilist, returns whether an edge was added.
94 * When a non-null part array is supplied with part indices for each atom,
95 * edges are only added when atoms have a different part index.
97 template <typename T>
98 static bool mk_igraph(t_graph *g, int ftype, const T &il,
99 int at_start, int at_end,
100 const int *part)
102 int i, j, np;
103 int end;
104 bool addedEdge = false;
106 end = il.size();
108 i = 0;
109 while (i < end)
111 np = interaction_function[ftype].nratoms;
113 if (np > 1 && il.iatoms[i + 1] >= at_start && il.iatoms[i + 1] < at_end)
115 if (il.iatoms[i + np] >= at_end)
117 gmx_fatal(FARGS,
118 "Molecule in topology has atom numbers below and "
119 "above natoms (%d).\n"
120 "You are probably trying to use a trajectory which does "
121 "not match the first %d atoms of the run input file.\n"
122 "You can make a matching run input file with gmx convert-tpr.",
123 at_end, at_end);
125 if (ftype == F_SETTLE)
127 /* Bond all the atoms in the settle */
128 add_gbond(g, il.iatoms[i + 1], il.iatoms[i + 2]);
129 add_gbond(g, il.iatoms[i + 1], il.iatoms[i + 3]);
130 addedEdge = true;
132 else if (part == nullptr)
134 /* Simply add this bond */
135 for (j = 1; j < np; j++)
137 add_gbond(g, il.iatoms[i + j], il.iatoms[i + j+1]);
139 addedEdge = true;
141 else
143 /* Add this bond when it connects two unlinked parts of the graph */
144 for (j = 1; j < np; j++)
146 if (part[il.iatoms[i + j]] != part[il.iatoms[i + j+1]])
148 add_gbond(g, il.iatoms[i + j], il.iatoms[i + j+1]);
149 addedEdge = true;
155 i += np+1;
158 return addedEdge;
161 [[noreturn]] static void g_error(int line, const char *file)
163 gmx_fatal(FARGS, "Trying to print nonexistent graph (file %s, line %d)",
164 file, line);
166 #define GCHECK(g) if ((g) == NULL) g_error(__LINE__, __FILE__)
168 void p_graph(FILE *log, const char *title, t_graph *g)
170 int i, j;
171 const char *cc[egcolNR] = { "W", "G", "B" };
173 GCHECK(g);
174 fprintf(log, "graph: %s\n", title);
175 fprintf(log, "nnodes: %d\n", g->nnodes);
176 fprintf(log, "nbound: %d\n", g->nbound);
177 fprintf(log, "start: %d\n", g->at_start);
178 fprintf(log, "end: %d\n", g->at_end);
179 fprintf(log, " atom shiftx shifty shiftz C nedg e1 e2 etc.\n");
180 for (i = 0; (i < g->nnodes); i++)
182 if (g->nedge[i] > 0)
184 fprintf(log, "%5d%7d%7d%7d %1s%5d", g->at_start+i+1,
185 g->ishift[g->at_start+i][XX],
186 g->ishift[g->at_start+i][YY],
187 g->ishift[g->at_start+i][ZZ],
188 (g->negc > 0) ? cc[g->egc[i]] : " ",
189 g->nedge[i]);
190 for (j = 0; (j < g->nedge[i]); j++)
192 fprintf(log, " %5d", g->edge[i][j]+1);
194 fprintf(log, "\n");
197 fflush(log);
200 template <typename T>
201 static void calc_1se(t_graph *g, int ftype, const T &il,
202 int nbond[], int at_start, int at_end)
204 int k, nratoms, end, j;
206 end = il.size();
208 for (j = 0; (j < end); j += nratoms + 1)
210 nratoms = interaction_function[ftype].nratoms;
212 if (ftype == F_SETTLE)
214 const int iaa = il.iatoms[j + 1];
215 if (iaa >= at_start && iaa < at_end)
217 nbond[iaa] += 2;
218 nbond[il.iatoms[j + 2]] += 1;
219 nbond[il.iatoms[j + 3]] += 1;
220 g->at_start = std::min(g->at_start, iaa);
221 g->at_end = std::max(g->at_end, iaa+2+1);
224 else
226 for (k = 1; (k <= nratoms); k++)
228 const int iaa = il.iatoms[j + k];
229 if (iaa >= at_start && iaa < at_end)
231 g->at_start = std::min(g->at_start, iaa);
232 g->at_end = std::max(g->at_end, iaa+1);
233 /* When making the graph we (might) link all atoms in an interaction
234 * sequentially. Therefore the end atoms add 1 to the count,
235 * the middle atoms 2.
237 if (k == 1 || k == nratoms)
239 nbond[iaa] += 1;
241 else
243 nbond[iaa] += 2;
251 template <typename T>
252 static int calc_start_end(FILE *fplog, t_graph *g, const T il[],
253 int at_start, int at_end,
254 int nbond[])
256 int i, nnb, nbtot;
258 g->at_start = at_end;
259 g->at_end = 0;
261 /* First add all the real bonds: they should determine the molecular
262 * graph.
264 for (i = 0; (i < F_NRE); i++)
266 if (interaction_function[i].flags & IF_CHEMBOND)
268 calc_1se(g, i, il[i], nbond, at_start, at_end);
271 /* Then add all the other interactions in fixed lists, but first
272 * check to see what's there already.
274 for (i = 0; (i < F_NRE); i++)
276 if (!(interaction_function[i].flags & IF_CHEMBOND))
278 calc_1se(g, i, il[i], nbond, at_start, at_end);
282 nnb = 0;
283 nbtot = 0;
284 for (i = g->at_start; (i < g->at_end); i++)
286 nbtot += nbond[i];
287 nnb = std::max(nnb, nbond[i]);
289 if (fplog)
291 fprintf(fplog, "Max number of connections per atom is %d\n", nnb);
292 fprintf(fplog, "Total number of connections is %d\n", nbtot);
294 return nbtot;
299 static void compact_graph(FILE *fplog, t_graph *g)
301 int i, j, n, max_nedge;
303 max_nedge = 0;
304 n = 0;
305 for (i = 0; i < g->nnodes; i++)
307 for (j = 0; j < g->nedge[i]; j++)
309 g->edge[0][n++] = g->edge[i][j];
311 max_nedge = std::max(max_nedge, g->nedge[i]);
313 srenew(g->edge[0], n);
314 /* set pointers after srenew because edge[0] might move */
315 for (i = 1; i < g->nnodes; i++)
317 g->edge[i] = g->edge[i-1] + g->nedge[i-1];
320 if (fplog)
322 fprintf(fplog, "Max number of graph edges per atom is %d\n",
323 max_nedge);
324 fprintf(fplog, "Total number of graph edges is %d\n", n);
328 static gmx_bool determine_graph_parts(t_graph *g, int *part)
330 int i, e;
331 int nchanged;
332 int at_i, *at_i2;
333 gmx_bool bMultiPart;
335 /* Initialize the part array with all entries different */
336 for (at_i = g->at_start; at_i < g->at_end; at_i++)
338 part[at_i] = at_i;
341 /* Loop over the graph until the part array is fixed */
344 bMultiPart = FALSE;
345 nchanged = 0;
346 for (i = 0; (i < g->nnodes); i++)
348 at_i = g->at_start + i;
349 at_i2 = g->edge[i];
350 for (e = 0; e < g->nedge[i]; e++)
352 /* Set part for both nodes to the minimum */
353 if (part[at_i2[e]] > part[at_i])
355 part[at_i2[e]] = part[at_i];
356 nchanged++;
358 else if (part[at_i2[e]] < part[at_i])
360 part[at_i] = part[at_i2[e]];
361 nchanged++;
364 if (part[at_i] != part[g->at_start])
366 bMultiPart = TRUE;
369 if (debug)
371 fprintf(debug, "graph part[] nchanged=%d, bMultiPart=%s\n",
372 nchanged, gmx::boolToString(bMultiPart));
375 while (nchanged > 0);
377 return bMultiPart;
380 template <typename T>
381 static void
382 mk_graph_ilist(FILE *fplog,
383 const T *ilist, int at_start, int at_end,
384 gmx_bool bShakeOnly, gmx_bool bSettle,
385 t_graph *g)
387 int *nbond;
388 int i, nbtot;
389 gmx_bool bMultiPart;
391 /* The naming is somewhat confusing, but we need g->at0 and g->at1
392 * for shifthing coordinates to a new array (not in place) when
393 * some atoms are not connected by the graph, which runs from
394 * g->at_start (>= g->at0) to g->at_end (<= g->at1).
396 g->at0 = at_start;
397 g->at1 = at_end;
398 g->parts = t_graph::BondedParts::Single;
400 snew(nbond, at_end);
401 nbtot = calc_start_end(fplog, g, ilist, at_start, at_end, nbond);
403 if (g->at_start >= g->at_end)
405 g->at_start = at_start;
406 g->at_end = at_end;
407 g->nnodes = 0;
408 g->nbound = 0;
410 else
412 g->nnodes = g->at_end - g->at_start;
413 snew(g->nedge, g->nnodes);
414 snew(g->edge, g->nnodes);
415 /* Allocate a single array and set pointers into it */
416 snew(g->edge[0], nbtot);
417 for (i = 1; (i < g->nnodes); i++)
419 g->edge[i] = g->edge[i-1] + nbond[g->at_start+i-1];
422 if (!bShakeOnly)
424 /* First add all the real bonds: they should determine the molecular
425 * graph.
427 for (i = 0; (i < F_NRE); i++)
429 if (interaction_function[i].flags & IF_CHEMBOND)
431 mk_igraph(g, i, ilist[i], at_start, at_end, nullptr);
435 /* Determine of which separated parts the IF_CHEMBOND graph consists.
436 * Store the parts in the nbond array.
438 bMultiPart = determine_graph_parts(g, nbond);
440 if (bMultiPart)
442 /* Then add all the other interactions in fixed lists,
443 * but only when they connect parts of the graph
444 * that are not connected through IF_CHEMBOND interactions.
446 bool addedEdge = false;
447 for (i = 0; (i < F_NRE); i++)
449 if (!(interaction_function[i].flags & IF_CHEMBOND))
451 bool addedEdgeForType =
452 mk_igraph(g, i, ilist[i], at_start, at_end, nbond);
453 addedEdge = (addedEdge || addedEdgeForType);
457 if (addedEdge)
459 g->parts = t_graph::BondedParts::MultipleConnected;
461 else
463 g->parts = t_graph::BondedParts::MultipleDisconnected;
467 /* Removed all the unused space from the edge array */
468 compact_graph(fplog, g);
470 else
472 /* This is a special thing used in splitter.c to generate shake-blocks */
473 mk_igraph(g, F_CONSTR, ilist[F_CONSTR], at_start, at_end, nullptr);
474 if (bSettle)
476 mk_igraph(g, F_SETTLE, ilist[F_SETTLE], at_start, at_end, nullptr);
479 g->nbound = 0;
480 for (i = 0; (i < g->nnodes); i++)
482 if (g->nedge[i] > 0)
484 g->nbound++;
489 g->negc = 0;
490 g->egc = nullptr;
492 sfree(nbond);
494 snew(g->ishift, g->at1);
496 if (gmx_debug_at)
498 p_graph(debug, "graph", g);
502 void mk_graph_moltype(const gmx_moltype_t &moltype,
503 t_graph *g)
505 mk_graph_ilist(nullptr, moltype.ilist.data(), 0, moltype.atoms.nr,
506 FALSE, FALSE,
510 t_graph *mk_graph(FILE *fplog,
511 const t_idef *idef, int at_start, int at_end,
512 gmx_bool bShakeOnly, gmx_bool bSettle)
514 t_graph *g;
516 snew(g, 1);
518 mk_graph_ilist(fplog, idef->il, at_start, at_end, bShakeOnly, bSettle, g);
520 return g;
523 void done_graph(t_graph *g)
525 GCHECK(g);
526 if (g->nnodes > 0)
528 sfree(g->nedge);
529 sfree(g->edge[0]);
530 sfree(g->edge);
531 sfree(g->egc);
533 sfree(g->ishift);
536 /************************************************************
538 * S H I F T C A L C U L A T I O N C O D E
540 ************************************************************/
542 static void mk_1shift_tric(int npbcdim, const matrix box, const rvec hbox,
543 const rvec xi, const rvec xj, const int *mi, int *mj)
545 /* Calculate periodicity for triclinic box... */
546 int m, d;
547 rvec dx;
549 rvec_sub(xi, xj, dx);
551 mj[ZZ] = 0;
552 for (m = npbcdim-1; (m >= 0); m--)
554 /* If dx < hbox, then xj will be reduced by box, so that
555 * xi - xj will be bigger
557 if (dx[m] < -hbox[m])
559 mj[m] = mi[m]-1;
560 for (d = m-1; d >= 0; d--)
562 dx[d] += box[m][d];
565 else if (dx[m] >= hbox[m])
567 mj[m] = mi[m]+1;
568 for (d = m-1; d >= 0; d--)
570 dx[d] -= box[m][d];
573 else
575 mj[m] = mi[m];
580 static void mk_1shift(int npbcdim, const rvec hbox, const rvec xi, const rvec xj,
581 const int *mi, int *mj)
583 /* Calculate periodicity for rectangular box... */
584 int m;
585 rvec dx;
587 rvec_sub(xi, xj, dx);
589 mj[ZZ] = 0;
590 for (m = 0; (m < npbcdim); m++)
592 /* If dx < hbox, then xj will be reduced by box, so that
593 * xi - xj will be bigger
595 if (dx[m] < -hbox[m])
597 mj[m] = mi[m]-1;
599 else if (dx[m] >= hbox[m])
601 mj[m] = mi[m]+1;
603 else
605 mj[m] = mi[m];
610 static void mk_1shift_screw(const matrix box, const rvec hbox,
611 const rvec xi, const rvec xj, const int *mi, int *mj)
613 /* Calculate periodicity for rectangular box... */
614 int signi, m;
615 rvec dx;
617 if ((mi[XX] > 0 && mi[XX] % 2 == 1) ||
618 (mi[XX] < 0 && -mi[XX] % 2 == 1))
620 signi = -1;
622 else
624 signi = 1;
627 rvec_sub(xi, xj, dx);
629 if (dx[XX] < -hbox[XX])
631 mj[XX] = mi[XX] - 1;
633 else if (dx[XX] >= hbox[XX])
635 mj[XX] = mi[XX] + 1;
637 else
639 mj[XX] = mi[XX];
641 if (mj[XX] != mi[XX])
643 /* Rotate */
644 dx[YY] = xi[YY] - (box[YY][YY] + box[ZZ][YY] - xj[YY]);
645 dx[ZZ] = xi[ZZ] - (box[ZZ][ZZ] - xj[ZZ]);
647 for (m = 1; (m < DIM); m++)
649 /* The signs are taken such that we can first shift x and rotate
650 * and then shift y and z.
652 if (dx[m] < -hbox[m])
654 mj[m] = mi[m] - signi;
656 else if (dx[m] >= hbox[m])
658 mj[m] = mi[m] + signi;
660 else
662 mj[m] = mi[m];
667 static int mk_grey(egCol egc[], t_graph *g, int *AtomI,
668 int npbcdim, const matrix box, const rvec x[], int *nerror)
670 int m, j, ng, ai, aj, g0;
671 rvec dx, hbox;
672 gmx_bool bTriclinic;
673 ivec is_aj;
674 t_pbc pbc;
676 for (m = 0; (m < DIM); m++)
678 hbox[m] = box[m][m]*0.5;
680 bTriclinic = TRICLINIC(box);
682 g0 = g->at_start;
683 ng = 0;
684 ai = g0 + *AtomI;
686 /* Loop over all the bonds */
687 for (j = 0; (j < g->nedge[ai-g0]); j++)
689 aj = g->edge[ai-g0][j];
690 /* If there is a white one, make it grey and set pbc */
691 if (g->bScrewPBC)
693 mk_1shift_screw(box, hbox, x[ai], x[aj], g->ishift[ai], is_aj);
695 else if (bTriclinic)
697 mk_1shift_tric(npbcdim, box, hbox, x[ai], x[aj], g->ishift[ai], is_aj);
699 else
701 mk_1shift(npbcdim, hbox, x[ai], x[aj], g->ishift[ai], is_aj);
704 if (egc[aj-g0] == egcolWhite)
706 if (aj - g0 < *AtomI)
708 *AtomI = aj - g0;
710 egc[aj-g0] = egcolGrey;
712 copy_ivec(is_aj, g->ishift[aj]);
714 ng++;
716 else if ((is_aj[XX] != g->ishift[aj][XX]) ||
717 (is_aj[YY] != g->ishift[aj][YY]) ||
718 (is_aj[ZZ] != g->ishift[aj][ZZ]))
720 if (gmx_debug_at)
722 set_pbc(&pbc, -1, box);
723 pbc_dx(&pbc, x[ai], x[aj], dx);
724 fprintf(debug, "mk_grey: shifts for atom %d due to atom %d\n"
725 "are (%d,%d,%d), should be (%d,%d,%d)\n"
726 "dx = (%g,%g,%g)\n",
727 aj+1, ai+1, is_aj[XX], is_aj[YY], is_aj[ZZ],
728 g->ishift[aj][XX], g->ishift[aj][YY], g->ishift[aj][ZZ],
729 dx[XX], dx[YY], dx[ZZ]);
731 (*nerror)++;
734 return ng;
737 static int first_colour(int fC, egCol Col, t_graph *g, const egCol egc[])
738 /* Return the first node with colour Col starting at fC.
739 * return -1 if none found.
742 int i;
744 for (i = fC; (i < g->nnodes); i++)
746 if ((g->nedge[i] > 0) && (egc[i] == Col))
748 return i;
752 return -1;
755 /* Returns the maximum length of the graph edges for coordinates x */
756 static real maxEdgeLength(const t_graph g,
757 int ePBC,
758 const matrix box,
759 const rvec x[])
761 t_pbc pbc;
763 set_pbc(&pbc, ePBC, box);
765 real maxEdgeLength2 = 0;
767 for (int node = 0; node < g.nnodes; node++)
769 for (int edge = 0; edge < g.nedge[node]; edge++)
771 int nodeJ = g.edge[node][edge];
772 rvec dx;
773 pbc_dx(&pbc, x[g.at0 + node], x[g.at0 + nodeJ], dx);
774 maxEdgeLength2 = std::max(maxEdgeLength2, norm2(dx));
778 return std::sqrt(maxEdgeLength2);
781 void mk_mshift(FILE *log, t_graph *g, int ePBC,
782 const matrix box, const rvec x[])
784 static int nerror_tot = 0;
785 int npbcdim;
786 int ng, nnodes, i;
787 int nW, nG, nB; /* Number of Grey, Black, White */
788 int fW, fG; /* First of each category */
789 int nerror = 0;
791 g->bScrewPBC = (ePBC == epbcSCREW);
793 if (ePBC == epbcXY)
795 npbcdim = 2;
797 else
799 npbcdim = 3;
802 GCHECK(g);
803 /* This puts everything in the central box, that is does not move it
804 * at all. If we return without doing this for a system without bonds
805 * (i.e. only settles) all water molecules are moved to the opposite octant
807 for (i = g->at0; (i < g->at1); i++)
809 g->ishift[i][XX] = g->ishift[i][YY] = g->ishift[i][ZZ] = 0;
812 if (!g->nbound)
814 return;
817 nnodes = g->nnodes;
818 if (nnodes > g->negc)
820 g->negc = nnodes;
821 srenew(g->egc, g->negc);
823 memset(g->egc, 0, static_cast<size_t>(nnodes*sizeof(g->egc[0])));
825 nW = g->nbound;
826 nG = 0;
827 nB = 0;
829 fW = 0;
831 /* We even have a loop invariant:
832 * nW+nG+nB == g->nbound
834 #ifdef DEBUG2
835 fprintf(log, "Starting W loop\n");
836 #endif
837 while (nW > 0)
839 /* Find the first white, this will allways be a larger
840 * number than before, because no nodes are made white
841 * in the loop
843 if ((fW = first_colour(fW, egcolWhite, g, g->egc)) == -1)
845 gmx_fatal(FARGS, "No WHITE nodes found while nW=%d\n", nW);
848 /* Make the first white node grey */
849 g->egc[fW] = egcolGrey;
850 nG++;
851 nW--;
853 /* Initial value for the first grey */
854 fG = fW;
855 #ifdef DEBUG2
856 fprintf(log, "Starting G loop (nW=%d, nG=%d, nB=%d, total %d)\n",
857 nW, nG, nB, nW+nG+nB);
858 #endif
859 while (nG > 0)
861 if ((fG = first_colour(fG, egcolGrey, g, g->egc)) == -1)
863 gmx_fatal(FARGS, "No GREY nodes found while nG=%d\n", nG);
866 /* Make the first grey node black */
867 g->egc[fG] = egcolBlack;
868 nB++;
869 nG--;
871 /* Make all the neighbours of this black node grey
872 * and set their periodicity
874 ng = mk_grey(g->egc, g, &fG, npbcdim, box, x, &nerror);
875 /* ng is the number of white nodes made grey */
876 nG += ng;
877 nW -= ng;
880 if (nerror > 0)
882 /* We use a threshold of 0.25*boxSize for generating a fatal error
883 * to allow removing PBC for systems with periodic molecules.
885 * TODO: Consider a better solution for systems with periodic
886 * molecules. Ideally analysis tools should only ask to make
887 * non-periodic molecules whole in a system with periodic mols.
889 constexpr real c_relativeDistanceThreshold = 0.25;
891 int numPbcDimensions = ePBC2npbcdim(ePBC);
892 GMX_RELEASE_ASSERT(numPbcDimensions > 0, "Expect PBC with graph");
893 real minBoxSize = norm(box[XX]);
894 for (int d = 1; d < numPbcDimensions; d++)
896 minBoxSize = std::min(minBoxSize, norm(box[d]));
898 real maxDistance = maxEdgeLength(*g, ePBC, box, x);
899 if (maxDistance >= c_relativeDistanceThreshold*minBoxSize)
901 std::string mesg = gmx::formatString("There are inconsistent shifts over periodic boundaries in a molecule type consisting of %d atoms. The longest distance involved in such interactions is %.3f nm which is %s half the box length.",
902 g->at1 - g->at0, maxDistance,
903 maxDistance >= 0.5*minBoxSize ? "above" : "close to");
905 switch (g->parts)
907 case t_graph::BondedParts::MultipleConnected:
908 /* Ideally we should check if the long distances are
909 * actually between the parts, but that would require
910 * a lot of extra code.
912 mesg += " This molecule type consists of muliple parts, e.g. monomers, that are connected by interactions that are not chemical bonds, e.g. restraints. Such systems can not be treated. The only solution is increasing the box size.";
913 break;
914 default:
915 mesg += " Either you have excessively large distances between atoms in bonded interactions or your system is exploding.";
917 gmx_fatal(FARGS, "%s", mesg.c_str());
920 /* The most likely reason for arriving here is a periodic molecule. */
922 nerror_tot++;
923 if (nerror_tot <= 100)
925 fprintf(stderr, "There were %d inconsistent shifts. Check your topology\n",
926 nerror);
927 if (log)
929 fprintf(log, "There were %d inconsistent shifts. Check your topology\n",
930 nerror);
933 if (nerror_tot == 100)
935 fprintf(stderr, "Will stop reporting inconsistent shifts\n");
936 if (log)
938 fprintf(log, "Will stop reporting inconsistent shifts\n");
944 /************************************************************
946 * A C T U A L S H I F T C O D E
948 ************************************************************/
950 void shift_x(const t_graph *g, const matrix box, const rvec x[], rvec x_s[])
952 ivec *is;
953 int g0, g1;
954 int j, tx, ty, tz;
956 GCHECK(g);
957 g0 = g->at_start;
958 g1 = g->at_end;
959 is = g->ishift;
961 for (j = g->at0; j < g0; j++)
963 copy_rvec(x[j], x_s[j]);
966 if (g->bScrewPBC)
968 for (j = g0; (j < g1); j++)
970 tx = is[j][XX];
971 ty = is[j][YY];
972 tz = is[j][ZZ];
974 if ((tx > 0 && tx % 2 == 1) ||
975 (tx < 0 && -tx %2 == 1))
977 x_s[j][XX] = x[j][XX] + tx*box[XX][XX];
978 x_s[j][YY] = box[YY][YY] + box[ZZ][YY] - x[j][YY];
979 x_s[j][ZZ] = box[ZZ][ZZ] - x[j][ZZ];
981 else
983 x_s[j][XX] = x[j][XX];
985 x_s[j][YY] = x[j][YY] + ty*box[YY][YY] + tz*box[ZZ][YY];
986 x_s[j][ZZ] = x[j][ZZ] + tz*box[ZZ][ZZ];
989 else if (TRICLINIC(box))
991 for (j = g0; (j < g1); j++)
993 tx = is[j][XX];
994 ty = is[j][YY];
995 tz = is[j][ZZ];
997 x_s[j][XX] = x[j][XX]+tx*box[XX][XX]+ty*box[YY][XX]+tz*box[ZZ][XX];
998 x_s[j][YY] = x[j][YY]+ty*box[YY][YY]+tz*box[ZZ][YY];
999 x_s[j][ZZ] = x[j][ZZ]+tz*box[ZZ][ZZ];
1002 else
1004 for (j = g0; (j < g1); j++)
1006 tx = is[j][XX];
1007 ty = is[j][YY];
1008 tz = is[j][ZZ];
1010 x_s[j][XX] = x[j][XX]+tx*box[XX][XX];
1011 x_s[j][YY] = x[j][YY]+ty*box[YY][YY];
1012 x_s[j][ZZ] = x[j][ZZ]+tz*box[ZZ][ZZ];
1016 for (j = g1; j < g->at1; j++)
1018 copy_rvec(x[j], x_s[j]);
1022 void shift_self(const t_graph *g, const matrix box, rvec x[])
1024 ivec *is;
1025 int g0, g1;
1026 int j, tx, ty, tz;
1028 if (g->bScrewPBC)
1030 gmx_incons("screw pbc not implemented for shift_self");
1033 g0 = g->at_start;
1034 g1 = g->at_end;
1035 is = g->ishift;
1037 #ifdef DEBUG
1038 fprintf(stderr, "Shifting atoms %d to %d\n", g0, g0+gn);
1039 #endif
1040 if (TRICLINIC(box))
1042 for (j = g0; (j < g1); j++)
1044 tx = is[j][XX];
1045 ty = is[j][YY];
1046 tz = is[j][ZZ];
1048 x[j][XX] = x[j][XX]+tx*box[XX][XX]+ty*box[YY][XX]+tz*box[ZZ][XX];
1049 x[j][YY] = x[j][YY]+ty*box[YY][YY]+tz*box[ZZ][YY];
1050 x[j][ZZ] = x[j][ZZ]+tz*box[ZZ][ZZ];
1053 else
1055 for (j = g0; (j < g1); j++)
1057 tx = is[j][XX];
1058 ty = is[j][YY];
1059 tz = is[j][ZZ];
1061 x[j][XX] = x[j][XX]+tx*box[XX][XX];
1062 x[j][YY] = x[j][YY]+ty*box[YY][YY];
1063 x[j][ZZ] = x[j][ZZ]+tz*box[ZZ][ZZ];
1068 void unshift_x(const t_graph *g, const matrix box, rvec x[], const rvec x_s[])
1070 ivec *is;
1071 int g0, g1;
1072 int j, tx, ty, tz;
1074 if (g->bScrewPBC)
1076 gmx_incons("screw pbc not implemented (yet) for unshift_x");
1079 g0 = g->at_start;
1080 g1 = g->at_end;
1081 is = g->ishift;
1083 for (j = g->at0; j < g0; j++)
1085 copy_rvec(x_s[j], x[j]);
1088 if (TRICLINIC(box))
1090 for (j = g0; (j < g1); j++)
1092 tx = is[j][XX];
1093 ty = is[j][YY];
1094 tz = is[j][ZZ];
1096 x[j][XX] = x_s[j][XX]-tx*box[XX][XX]-ty*box[YY][XX]-tz*box[ZZ][XX];
1097 x[j][YY] = x_s[j][YY]-ty*box[YY][YY]-tz*box[ZZ][YY];
1098 x[j][ZZ] = x_s[j][ZZ]-tz*box[ZZ][ZZ];
1101 else
1103 for (j = g0; (j < g1); j++)
1105 tx = is[j][XX];
1106 ty = is[j][YY];
1107 tz = is[j][ZZ];
1109 x[j][XX] = x_s[j][XX]-tx*box[XX][XX];
1110 x[j][YY] = x_s[j][YY]-ty*box[YY][YY];
1111 x[j][ZZ] = x_s[j][ZZ]-tz*box[ZZ][ZZ];
1115 for (j = g1; j < g->at1; j++)
1117 copy_rvec(x_s[j], x[j]);
1121 void unshift_self(const t_graph *g, const matrix box, rvec x[])
1123 ivec *is;
1124 int g0, g1;
1125 int j, tx, ty, tz;
1127 if (g->bScrewPBC)
1129 gmx_incons("screw pbc not implemented for unshift_self");
1132 g0 = g->at_start;
1133 g1 = g->at_end;
1134 is = g->ishift;
1136 if (TRICLINIC(box))
1138 for (j = g0; (j < g1); j++)
1140 tx = is[j][XX];
1141 ty = is[j][YY];
1142 tz = is[j][ZZ];
1144 x[j][XX] = x[j][XX]-tx*box[XX][XX]-ty*box[YY][XX]-tz*box[ZZ][XX];
1145 x[j][YY] = x[j][YY]-ty*box[YY][YY]-tz*box[ZZ][YY];
1146 x[j][ZZ] = x[j][ZZ]-tz*box[ZZ][ZZ];
1149 else
1151 for (j = g0; (j < g1); j++)
1153 tx = is[j][XX];
1154 ty = is[j][YY];
1155 tz = is[j][ZZ];
1157 x[j][XX] = x[j][XX]-tx*box[XX][XX];
1158 x[j][YY] = x[j][YY]-ty*box[YY][YY];
1159 x[j][ZZ] = x[j][ZZ]-tz*box[ZZ][ZZ];
1163 #undef GCHECK