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, 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.
45 #include "gromacs/legacyheaders/types/ifunc.h"
46 #include "gromacs/math/vec.h"
47 #include "gromacs/pbcutil/pbc.h"
48 #include "gromacs/utility/fatalerror.h"
49 #include "gromacs/utility/smalloc.h"
51 /************************************************************
53 * S H I F T U T I L I T I E S
55 ************************************************************/
58 /************************************************************
60 * G R A P H G E N E R A T I O N C O D E
62 ************************************************************/
64 static void add_gbond(t_graph *g, atom_id a0, atom_id a1)
70 inda0 = a0 - g->at_start;
71 inda1 = a1 - g->at_start;
73 /* Search for a direct edge between a0 and a1.
74 * All egdes are bidirectional, so we only need to search one way.
76 for (i = 0; (i < g->nedge[inda0] && !bFound); i++)
78 bFound = (g->edge[inda0][i] == a1);
83 g->edge[inda0][g->nedge[inda0]++] = a1;
84 g->edge[inda1][g->nedge[inda1]++] = a0;
88 static void mk_igraph(t_graph *g, int ftype, t_ilist *il,
89 int at_start, int at_end,
102 np = interaction_function[ftype].nratoms;
104 if (ia[1] >= at_start && ia[1] < at_end)
106 if (ia[np] >= at_end)
109 "Molecule in topology has atom numbers below and "
110 "above natoms (%d).\n"
111 "You are probably trying to use a trajectory which does "
112 "not match the first %d atoms of the run input file.\n"
113 "You can make a matching run input file with gmx convert-tpr.",
116 if (ftype == F_SETTLE)
118 /* Bond all the atoms in the settle */
119 add_gbond(g, ia[1], ia[2]);
120 add_gbond(g, ia[1], ia[3]);
122 else if (part == NULL)
124 /* Simply add this bond */
125 for (j = 1; j < np; j++)
127 add_gbond(g, ia[j], ia[j+1]);
132 /* Add this bond when it connects two unlinked parts of the graph */
133 for (j = 1; j < np; j++)
135 if (part[ia[j]] != part[ia[j+1]])
137 add_gbond(g, ia[j], ia[j+1]);
147 gmx_noreturn static void g_error(int line, const char *file)
149 gmx_fatal(FARGS, "Tring to print non existant graph (file %s, line %d)",
152 #define GCHECK(g) if (g == NULL) g_error(__LINE__, __FILE__)
154 void p_graph(FILE *log, const char *title, t_graph *g)
157 const char *cc[egcolNR] = { "W", "G", "B" };
160 fprintf(log, "graph: %s\n", title);
161 fprintf(log, "nnodes: %d\n", g->nnodes);
162 fprintf(log, "nbound: %d\n", g->nbound);
163 fprintf(log, "start: %d\n", g->at_start);
164 fprintf(log, "end: %d\n", g->at_end);
165 fprintf(log, " atom shiftx shifty shiftz C nedg e1 e2 etc.\n");
166 for (i = 0; (i < g->nnodes); i++)
170 fprintf(log, "%5d%7d%7d%7d %1s%5d", g->at_start+i+1,
171 g->ishift[g->at_start+i][XX],
172 g->ishift[g->at_start+i][YY],
173 g->ishift[g->at_start+i][ZZ],
174 (g->negc > 0) ? cc[g->egc[i]] : " ",
176 for (j = 0; (j < g->nedge[i]); j++)
178 fprintf(log, " %5d", g->edge[i][j]+1);
186 static void calc_1se(t_graph *g, int ftype, t_ilist *il,
187 int nbond[], int at_start, int at_end)
189 int k, nratoms, end, j;
195 for (j = 0; (j < end); j += nratoms+1, ia += nratoms+1)
197 nratoms = interaction_function[ftype].nratoms;
199 if (ftype == F_SETTLE)
202 if (iaa >= at_start && iaa < at_end)
207 g->at_start = std::min(g->at_start, iaa);
208 g->at_end = std::max(g->at_end, iaa+2+1);
213 for (k = 1; (k <= nratoms); k++)
216 if (iaa >= at_start && iaa < at_end)
218 g->at_start = std::min(g->at_start, iaa);
219 g->at_end = std::max(g->at_end, iaa+1);
220 /* When making the graph we (might) link all atoms in an interaction
221 * sequentially. Therefore the end atoms add 1 to the count,
222 * the middle atoms 2.
224 if (k == 1 || k == nratoms)
238 static int calc_start_end(FILE *fplog, t_graph *g, t_ilist il[],
239 int at_start, int at_end,
244 g->at_start = at_end;
247 /* First add all the real bonds: they should determine the molecular
250 for (i = 0; (i < F_NRE); i++)
252 if (interaction_function[i].flags & IF_CHEMBOND)
254 calc_1se(g, i, &il[i], nbond, at_start, at_end);
257 /* Then add all the other interactions in fixed lists, but first
258 * check to see what's there already.
260 for (i = 0; (i < F_NRE); i++)
262 if (!(interaction_function[i].flags & IF_CHEMBOND))
264 calc_1se(g, i, &il[i], nbond, at_start, at_end);
270 for (i = g->at_start; (i < g->at_end); i++)
273 nnb = std::max(nnb, nbond[i]);
277 fprintf(fplog, "Max number of connections per atom is %d\n", nnb);
278 fprintf(fplog, "Total number of connections is %d\n", nbtot);
285 static void compact_graph(FILE *fplog, t_graph *g)
287 int i, j, n, max_nedge;
291 for (i = 0; i < g->nnodes; i++)
293 for (j = 0; j < g->nedge[i]; j++)
295 g->edge[0][n++] = g->edge[i][j];
297 max_nedge = std::max(max_nedge, g->nedge[i]);
299 srenew(g->edge[0], n);
300 /* set pointers after srenew because edge[0] might move */
301 for (i = 1; i < g->nnodes; i++)
303 g->edge[i] = g->edge[i-1] + g->nedge[i-1];
308 fprintf(fplog, "Max number of graph edges per atom is %d\n",
310 fprintf(fplog, "Total number of graph edges is %d\n", n);
314 static gmx_bool determine_graph_parts(t_graph *g, int *part)
318 atom_id at_i, *at_i2;
321 /* Initialize the part array with all entries different */
322 for (at_i = g->at_start; at_i < g->at_end; at_i++)
327 /* Loop over the graph until the part array is fixed */
332 for (i = 0; (i < g->nnodes); i++)
334 at_i = g->at_start + i;
336 for (e = 0; e < g->nedge[i]; e++)
338 /* Set part for both nodes to the minimum */
339 if (part[at_i2[e]] > part[at_i])
341 part[at_i2[e]] = part[at_i];
344 else if (part[at_i2[e]] < part[at_i])
346 part[at_i] = part[at_i2[e]];
350 if (part[at_i] != part[g->at_start])
357 fprintf(debug, "graph part[] nchanged=%d, bMultiPart=%d\n",
358 nchanged, bMultiPart);
361 while (nchanged > 0);
366 void mk_graph_ilist(FILE *fplog,
367 t_ilist *ilist, int at_start, int at_end,
368 gmx_bool bShakeOnly, gmx_bool bSettle,
375 /* The naming is somewhat confusing, but we need g->at0 and g->at1
376 * for shifthing coordinates to a new array (not in place) when
377 * some atoms are not connected by the graph, which runs from
378 * g->at_start (>= g->at0) to g->at_end (<= g->at1).
384 nbtot = calc_start_end(fplog, g, ilist, at_start, at_end, nbond);
386 if (g->at_start >= g->at_end)
388 g->at_start = at_start;
395 g->nnodes = g->at_end - g->at_start;
396 snew(g->nedge, g->nnodes);
397 snew(g->edge, g->nnodes);
398 /* Allocate a single array and set pointers into it */
399 snew(g->edge[0], nbtot);
400 for (i = 1; (i < g->nnodes); i++)
402 g->edge[i] = g->edge[i-1] + nbond[g->at_start+i-1];
407 /* First add all the real bonds: they should determine the molecular
410 for (i = 0; (i < F_NRE); i++)
412 if (interaction_function[i].flags & IF_CHEMBOND)
414 mk_igraph(g, i, &(ilist[i]), at_start, at_end, NULL);
418 /* Determine of which separated parts the IF_CHEMBOND graph consists.
419 * Store the parts in the nbond array.
421 bMultiPart = determine_graph_parts(g, nbond);
425 /* Then add all the other interactions in fixed lists,
426 * but only when they connect parts of the graph
427 * that are not connected through IF_CHEMBOND interactions.
429 for (i = 0; (i < F_NRE); i++)
431 if (!(interaction_function[i].flags & IF_CHEMBOND))
433 mk_igraph(g, i, &(ilist[i]), at_start, at_end, nbond);
438 /* Removed all the unused space from the edge array */
439 compact_graph(fplog, g);
443 /* This is a special thing used in splitter.c to generate shake-blocks */
444 mk_igraph(g, F_CONSTR, &(ilist[F_CONSTR]), at_start, at_end, NULL);
447 mk_igraph(g, F_SETTLE, &(ilist[F_SETTLE]), at_start, at_end, NULL);
451 for (i = 0; (i < g->nnodes); i++)
465 snew(g->ishift, g->at1);
469 p_graph(debug, "graph", g);
473 t_graph *mk_graph(FILE *fplog,
474 t_idef *idef, int at_start, int at_end,
475 gmx_bool bShakeOnly, gmx_bool bSettle)
481 mk_graph_ilist(fplog, idef->il, at_start, at_end, bShakeOnly, bSettle, g);
486 void done_graph(t_graph *g)
499 /************************************************************
501 * S H I F T C A L C U L A T I O N C O D E
503 ************************************************************/
505 static void mk_1shift_tric(int npbcdim, matrix box, rvec hbox,
506 rvec xi, rvec xj, int *mi, int *mj)
508 /* Calculate periodicity for triclinic box... */
512 rvec_sub(xi, xj, dx);
515 for (m = npbcdim-1; (m >= 0); m--)
517 /* If dx < hbox, then xj will be reduced by box, so that
518 * xi - xj will be bigger
520 if (dx[m] < -hbox[m])
523 for (d = m-1; d >= 0; d--)
528 else if (dx[m] >= hbox[m])
531 for (d = m-1; d >= 0; d--)
543 static void mk_1shift(int npbcdim, rvec hbox, rvec xi, rvec xj, int *mi, int *mj)
545 /* Calculate periodicity for rectangular box... */
549 rvec_sub(xi, xj, dx);
552 for (m = 0; (m < npbcdim); 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])
561 else if (dx[m] >= hbox[m])
572 static void mk_1shift_screw(matrix box, rvec hbox,
573 rvec xi, rvec xj, int *mi, int *mj)
575 /* Calculate periodicity for rectangular box... */
579 if ((mi[XX] > 0 && mi[XX] % 2 == 1) ||
580 (mi[XX] < 0 && -mi[XX] % 2 == 1))
589 rvec_sub(xi, xj, dx);
591 if (dx[XX] < -hbox[XX])
595 else if (dx[XX] >= hbox[XX])
603 if (mj[XX] != mi[XX])
606 dx[YY] = xi[YY] - (box[YY][YY] + box[ZZ][YY] - xj[YY]);
607 dx[ZZ] = xi[ZZ] - (box[ZZ][ZZ] - xj[ZZ]);
609 for (m = 1; (m < DIM); m++)
611 /* The signs are taken such that we can first shift x and rotate
612 * and then shift y and z.
614 if (dx[m] < -hbox[m])
616 mj[m] = mi[m] - signi;
618 else if (dx[m] >= hbox[m])
620 mj[m] = mi[m] + signi;
629 static int mk_grey(egCol egc[], t_graph *g, int *AtomI,
630 int npbcdim, matrix box, rvec x[], int *nerror)
632 int m, j, ng, ai, aj, g0;
638 for (m = 0; (m < DIM); m++)
640 hbox[m] = box[m][m]*0.5;
642 bTriclinic = TRICLINIC(box);
648 /* Loop over all the bonds */
649 for (j = 0; (j < g->nedge[ai-g0]); j++)
651 aj = g->edge[ai-g0][j];
652 /* If there is a white one, make it grey and set pbc */
655 mk_1shift_screw(box, hbox, x[ai], x[aj], g->ishift[ai], is_aj);
659 mk_1shift_tric(npbcdim, box, hbox, x[ai], x[aj], g->ishift[ai], is_aj);
663 mk_1shift(npbcdim, hbox, x[ai], x[aj], g->ishift[ai], is_aj);
666 if (egc[aj-g0] == egcolWhite)
668 if (aj - g0 < *AtomI)
672 egc[aj-g0] = egcolGrey;
674 copy_ivec(is_aj, g->ishift[aj]);
678 else if ((is_aj[XX] != g->ishift[aj][XX]) ||
679 (is_aj[YY] != g->ishift[aj][YY]) ||
680 (is_aj[ZZ] != g->ishift[aj][ZZ]))
684 set_pbc(&pbc, -1, box);
685 pbc_dx(&pbc, x[ai], x[aj], dx);
686 fprintf(debug, "mk_grey: shifts for atom %d due to atom %d\n"
687 "are (%d,%d,%d), should be (%d,%d,%d)\n"
689 aj+1, ai+1, is_aj[XX], is_aj[YY], is_aj[ZZ],
690 g->ishift[aj][XX], g->ishift[aj][YY], g->ishift[aj][ZZ],
691 dx[XX], dx[YY], dx[ZZ]);
699 static int first_colour(int fC, egCol Col, t_graph *g, egCol egc[])
700 /* Return the first node with colour Col starting at fC.
701 * return -1 if none found.
706 for (i = fC; (i < g->nnodes); i++)
708 if ((g->nedge[i] > 0) && (egc[i] == Col))
717 void mk_mshift(FILE *log, t_graph *g, int ePBC, matrix box, rvec x[])
719 static int nerror_tot = 0;
722 int nW, nG, nB; /* Number of Grey, Black, White */
723 int fW, fG; /* First of each category */
726 g->bScrewPBC = (ePBC == epbcSCREW);
738 /* This puts everything in the central box, that is does not move it
739 * at all. If we return without doing this for a system without bonds
740 * (i.e. only settles) all water molecules are moved to the opposite octant
742 for (i = g->at0; (i < g->at1); i++)
744 g->ishift[i][XX] = g->ishift[i][YY] = g->ishift[i][ZZ] = 0;
753 if (nnodes > g->negc)
756 srenew(g->egc, g->negc);
758 memset(g->egc, 0, (size_t)(nnodes*sizeof(g->egc[0])));
766 /* We even have a loop invariant:
767 * nW+nG+nB == g->nbound
770 fprintf(log, "Starting W loop\n");
774 /* Find the first white, this will allways be a larger
775 * number than before, because no nodes are made white
778 if ((fW = first_colour(fW, egcolWhite, g, g->egc)) == -1)
780 gmx_fatal(FARGS, "No WHITE nodes found while nW=%d\n", nW);
783 /* Make the first white node grey */
784 g->egc[fW] = egcolGrey;
788 /* Initial value for the first grey */
791 fprintf(log, "Starting G loop (nW=%d, nG=%d, nB=%d, total %d)\n",
792 nW, nG, nB, nW+nG+nB);
796 if ((fG = first_colour(fG, egcolGrey, g, g->egc)) == -1)
798 gmx_fatal(FARGS, "No GREY nodes found while nG=%d\n", nG);
801 /* Make the first grey node black */
802 g->egc[fG] = egcolBlack;
806 /* Make all the neighbours of this black node grey
807 * and set their periodicity
809 ng = mk_grey(g->egc, g, &fG, npbcdim, box, x, &nerror);
810 /* ng is the number of white nodes made grey */
818 if (nerror_tot <= 100)
820 fprintf(stderr, "There were %d inconsistent shifts. Check your topology\n",
824 fprintf(log, "There were %d inconsistent shifts. Check your topology\n",
828 if (nerror_tot == 100)
830 fprintf(stderr, "Will stop reporting inconsistent shifts\n");
833 fprintf(log, "Will stop reporting inconsistent shifts\n");
839 /************************************************************
841 * A C T U A L S H I F T C O D E
843 ************************************************************/
845 void shift_x(t_graph *g, matrix box, rvec x[], rvec x_s[])
856 for (j = g->at0; j < g0; j++)
858 copy_rvec(x[j], x_s[j]);
863 for (j = g0; (j < g1); j++)
869 if ((tx > 0 && tx % 2 == 1) ||
870 (tx < 0 && -tx %2 == 1))
872 x_s[j][XX] = x[j][XX] + tx*box[XX][XX];
873 x_s[j][YY] = box[YY][YY] + box[ZZ][YY] - x[j][YY];
874 x_s[j][ZZ] = box[ZZ][ZZ] - x[j][ZZ];
878 x_s[j][XX] = x[j][XX];
880 x_s[j][YY] = x[j][YY] + ty*box[YY][YY] + tz*box[ZZ][YY];
881 x_s[j][ZZ] = x[j][ZZ] + tz*box[ZZ][ZZ];
884 else if (TRICLINIC(box))
886 for (j = g0; (j < g1); j++)
892 x_s[j][XX] = x[j][XX]+tx*box[XX][XX]+ty*box[YY][XX]+tz*box[ZZ][XX];
893 x_s[j][YY] = x[j][YY]+ty*box[YY][YY]+tz*box[ZZ][YY];
894 x_s[j][ZZ] = x[j][ZZ]+tz*box[ZZ][ZZ];
899 for (j = g0; (j < g1); j++)
905 x_s[j][XX] = x[j][XX]+tx*box[XX][XX];
906 x_s[j][YY] = x[j][YY]+ty*box[YY][YY];
907 x_s[j][ZZ] = x[j][ZZ]+tz*box[ZZ][ZZ];
911 for (j = g1; j < g->at1; j++)
913 copy_rvec(x[j], x_s[j]);
917 void shift_self(t_graph *g, matrix box, rvec x[])
925 gmx_incons("screw pbc not implemented for shift_self");
933 fprintf(stderr, "Shifting atoms %d to %d\n", g0, g0+gn);
937 for (j = g0; (j < g1); j++)
943 x[j][XX] = x[j][XX]+tx*box[XX][XX]+ty*box[YY][XX]+tz*box[ZZ][XX];
944 x[j][YY] = x[j][YY]+ty*box[YY][YY]+tz*box[ZZ][YY];
945 x[j][ZZ] = x[j][ZZ]+tz*box[ZZ][ZZ];
950 for (j = g0; (j < g1); j++)
956 x[j][XX] = x[j][XX]+tx*box[XX][XX];
957 x[j][YY] = x[j][YY]+ty*box[YY][YY];
958 x[j][ZZ] = x[j][ZZ]+tz*box[ZZ][ZZ];
963 void unshift_x(t_graph *g, matrix box, rvec x[], rvec x_s[])
971 gmx_incons("screw pbc not implemented (yet) for unshift_x");
978 for (j = g->at0; j < g0; j++)
980 copy_rvec(x_s[j], x[j]);
985 for (j = g0; (j < g1); j++)
991 x[j][XX] = x_s[j][XX]-tx*box[XX][XX]-ty*box[YY][XX]-tz*box[ZZ][XX];
992 x[j][YY] = x_s[j][YY]-ty*box[YY][YY]-tz*box[ZZ][YY];
993 x[j][ZZ] = x_s[j][ZZ]-tz*box[ZZ][ZZ];
998 for (j = g0; (j < g1); j++)
1004 x[j][XX] = x_s[j][XX]-tx*box[XX][XX];
1005 x[j][YY] = x_s[j][YY]-ty*box[YY][YY];
1006 x[j][ZZ] = x_s[j][ZZ]-tz*box[ZZ][ZZ];
1010 for (j = g1; j < g->at1; j++)
1012 copy_rvec(x_s[j], x[j]);
1016 void unshift_self(t_graph *g, matrix box, rvec x[])
1024 gmx_incons("screw pbc not implemented for unshift_self");
1033 for (j = g0; (j < g1); j++)
1039 x[j][XX] = x[j][XX]-tx*box[XX][XX]-ty*box[YY][XX]-tz*box[ZZ][XX];
1040 x[j][YY] = x[j][YY]-ty*box[YY][YY]-tz*box[ZZ][YY];
1041 x[j][ZZ] = x[j][ZZ]-tz*box[ZZ][ZZ];
1046 for (j = g0; (j < g1); j++)
1052 x[j][XX] = x[j][XX]-tx*box[XX][XX];
1053 x[j][YY] = x[j][YY]-ty*box[YY][YY];
1054 x[j][ZZ] = x[j][ZZ]-tz*box[ZZ][ZZ];