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 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
46 #include "gromacs/math/vec.h"
47 #include "gromacs/pbcutil/pbc.h"
48 #include "gromacs/topology/idef.h"
49 #include "gromacs/topology/ifunc.h"
50 #include "gromacs/topology/topology.h"
51 #include "gromacs/utility/fatalerror.h"
52 #include "gromacs/utility/smalloc.h"
53 #include "gromacs/utility/strconvert.h"
54 #include "gromacs/utility/stringutil.h"
56 /************************************************************
58 * S H I F T U T I L I T I E S
60 ************************************************************/
63 /************************************************************
65 * G R A P H G E N E R A T I O N C O D E
67 ************************************************************/
69 static void add_gbond(t_graph* g, int a0, int a1)
75 inda0 = a0 - g->at_start;
76 inda1 = a1 - g->at_start;
78 /* Search for a direct edge between a0 and a1.
79 * All egdes are bidirectional, so we only need to search one way.
81 for (i = 0; (i < g->nedge[inda0] && !bFound); i++)
83 bFound = (g->edge[inda0][i] == a1);
88 g->edge[inda0][g->nedge[inda0]++] = a1;
89 g->edge[inda1][g->nedge[inda1]++] = a0;
93 /* Make the actual graph for an ilist, returns whether an edge was added.
95 * When a non-null part array is supplied with part indices for each atom,
96 * edges are only added when atoms have a different part index.
99 static bool mk_igraph(t_graph* g, int ftype, const T& il, int at_start, int at_end, const int* part)
103 bool addedEdge = false;
110 np = interaction_function[ftype].nratoms;
112 if (np > 1 && il.iatoms[i + 1] >= at_start && il.iatoms[i + 1] < at_end)
114 if (il.iatoms[i + np] >= at_end)
117 "Molecule in topology has atom numbers below and "
118 "above natoms (%d).\n"
119 "You are probably trying to use a trajectory which does "
120 "not match the first %d atoms of the run input file.\n"
121 "You can make a matching run input file with gmx convert-tpr.",
124 if (ftype == F_SETTLE)
126 /* Bond all the atoms in the settle */
127 add_gbond(g, il.iatoms[i + 1], il.iatoms[i + 2]);
128 add_gbond(g, il.iatoms[i + 1], il.iatoms[i + 3]);
131 else if (part == nullptr)
133 /* Simply add this bond */
134 for (j = 1; j < np; j++)
136 add_gbond(g, il.iatoms[i + j], il.iatoms[i + j + 1]);
142 /* Add this bond when it connects two unlinked parts of the graph */
143 for (j = 1; j < np; j++)
145 if (part[il.iatoms[i + j]] != part[il.iatoms[i + j + 1]])
147 add_gbond(g, il.iatoms[i + j], il.iatoms[i + j + 1]);
160 [[noreturn]] static void g_error(int line, const char* file)
162 gmx_fatal(FARGS, "Trying to print nonexistent graph (file %s, line %d)", file, line);
166 g_error(__LINE__, __FILE__)
168 void p_graph(FILE* log, const char* title, t_graph* g)
171 const char* cc[egcolNR] = { "W", "G", "B" };
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++)
184 fprintf(log, "%5d%7d%7d%7d %1s%5d", g->at_start + i + 1, g->ishift[g->at_start + i][XX],
185 g->ishift[g->at_start + i][YY], g->ishift[g->at_start + i][ZZ],
186 (g->negc > 0) ? cc[g->egc[i]] : " ", g->nedge[i]);
187 for (j = 0; (j < g->nedge[i]); j++)
189 fprintf(log, " %5d", g->edge[i][j] + 1);
198 static void calc_1se(t_graph* g, int ftype, const T& il, int nbond[], int at_start, int at_end)
200 int k, nratoms, end, j;
204 for (j = 0; (j < end); j += nratoms + 1)
206 nratoms = interaction_function[ftype].nratoms;
208 if (ftype == F_SETTLE)
210 const int iaa = il.iatoms[j + 1];
211 if (iaa >= at_start && iaa < at_end)
214 nbond[il.iatoms[j + 2]] += 1;
215 nbond[il.iatoms[j + 3]] += 1;
216 g->at_start = std::min(g->at_start, iaa);
217 g->at_end = std::max(g->at_end, iaa + 2 + 1);
222 for (k = 1; (k <= nratoms); k++)
224 const int iaa = il.iatoms[j + k];
225 if (iaa >= at_start && iaa < at_end)
227 g->at_start = std::min(g->at_start, iaa);
228 g->at_end = std::max(g->at_end, iaa + 1);
229 /* When making the graph we (might) link all atoms in an interaction
230 * sequentially. Therefore the end atoms add 1 to the count,
231 * the middle atoms 2.
233 if (k == 1 || k == nratoms)
248 static int calc_start_end(FILE* fplog, t_graph* g, const T il[], int at_start, int at_end, int nbond[])
252 g->at_start = at_end;
255 /* First add all the real bonds: they should determine the molecular
258 for (i = 0; (i < F_NRE); i++)
260 if (interaction_function[i].flags & IF_CHEMBOND)
262 calc_1se(g, i, il[i], nbond, at_start, at_end);
265 /* Then add all the other interactions in fixed lists, but first
266 * check to see what's there already.
268 for (i = 0; (i < F_NRE); i++)
270 if (!(interaction_function[i].flags & IF_CHEMBOND))
272 calc_1se(g, i, il[i], nbond, at_start, at_end);
278 for (i = g->at_start; (i < g->at_end); i++)
281 nnb = std::max(nnb, nbond[i]);
285 fprintf(fplog, "Max number of connections per atom is %d\n", nnb);
286 fprintf(fplog, "Total number of connections is %d\n", nbtot);
292 static void compact_graph(FILE* fplog, t_graph* g)
294 int i, j, n, max_nedge;
298 for (i = 0; i < g->nnodes; i++)
300 for (j = 0; j < g->nedge[i]; j++)
302 g->edge[0][n++] = g->edge[i][j];
304 max_nedge = std::max(max_nedge, g->nedge[i]);
306 srenew(g->edge[0], n);
307 /* set pointers after srenew because edge[0] might move */
308 for (i = 1; i < g->nnodes; i++)
310 g->edge[i] = g->edge[i - 1] + g->nedge[i - 1];
315 fprintf(fplog, "Max number of graph edges per atom is %d\n", max_nedge);
316 fprintf(fplog, "Total number of graph edges is %d\n", n);
320 static gmx_bool determine_graph_parts(t_graph* g, int* part)
327 /* Initialize the part array with all entries different */
328 for (at_i = g->at_start; at_i < g->at_end; at_i++)
333 /* Loop over the graph until the part array is fixed */
338 for (i = 0; (i < g->nnodes); i++)
340 at_i = g->at_start + i;
342 for (e = 0; e < g->nedge[i]; e++)
344 /* Set part for both nodes to the minimum */
345 if (part[at_i2[e]] > part[at_i])
347 part[at_i2[e]] = part[at_i];
350 else if (part[at_i2[e]] < part[at_i])
352 part[at_i] = part[at_i2[e]];
356 if (part[at_i] != part[g->at_start])
363 fprintf(debug, "graph part[] nchanged=%d, bMultiPart=%s\n", nchanged,
364 gmx::boolToString(bMultiPart));
366 } while (nchanged > 0);
372 static void mk_graph_ilist(FILE* fplog,
384 /* The naming is somewhat confusing, but we need g->at0 and g->at1
385 * for shifthing coordinates to a new array (not in place) when
386 * some atoms are not connected by the graph, which runs from
387 * g->at_start (>= g->at0) to g->at_end (<= g->at1).
391 g->parts = t_graph::BondedParts::Single;
394 nbtot = calc_start_end(fplog, g, ilist, at_start, at_end, nbond);
396 if (g->at_start >= g->at_end)
398 g->at_start = at_start;
405 g->nnodes = g->at_end - g->at_start;
406 snew(g->nedge, g->nnodes);
407 snew(g->edge, g->nnodes);
408 /* Allocate a single array and set pointers into it */
409 snew(g->edge[0], nbtot);
410 for (i = 1; (i < g->nnodes); i++)
412 g->edge[i] = g->edge[i - 1] + nbond[g->at_start + i - 1];
417 /* First add all the real bonds: they should determine the molecular
420 for (i = 0; (i < F_NRE); i++)
422 if (interaction_function[i].flags & IF_CHEMBOND)
424 mk_igraph(g, i, ilist[i], at_start, at_end, nullptr);
428 /* Determine of which separated parts the IF_CHEMBOND graph consists.
429 * Store the parts in the nbond array.
431 bMultiPart = determine_graph_parts(g, nbond);
435 /* Then add all the other interactions in fixed lists,
436 * but only when they connect parts of the graph
437 * that are not connected through IF_CHEMBOND interactions.
439 bool addedEdge = false;
440 for (i = 0; (i < F_NRE); i++)
442 if (!(interaction_function[i].flags & IF_CHEMBOND))
444 bool addedEdgeForType = mk_igraph(g, i, ilist[i], at_start, at_end, nbond);
445 addedEdge = (addedEdge || addedEdgeForType);
451 g->parts = t_graph::BondedParts::MultipleConnected;
455 g->parts = t_graph::BondedParts::MultipleDisconnected;
459 /* Removed all the unused space from the edge array */
460 compact_graph(fplog, g);
464 /* This is a special thing used in splitter.c to generate shake-blocks */
465 mk_igraph(g, F_CONSTR, ilist[F_CONSTR], at_start, at_end, nullptr);
468 mk_igraph(g, F_SETTLE, ilist[F_SETTLE], at_start, at_end, nullptr);
472 for (i = 0; (i < g->nnodes); i++)
486 snew(g->ishift, g->at1);
490 p_graph(debug, "graph", g);
494 void mk_graph_moltype(const gmx_moltype_t& moltype, t_graph* g)
496 mk_graph_ilist(nullptr, moltype.ilist.data(), 0, moltype.atoms.nr, FALSE, FALSE, g);
499 t_graph* mk_graph(FILE* fplog, const t_idef* idef, int at_start, int at_end, gmx_bool bShakeOnly, gmx_bool bSettle)
505 mk_graph_ilist(fplog, idef->il, at_start, at_end, bShakeOnly, bSettle, g);
510 void done_graph(t_graph* g)
523 /************************************************************
525 * S H I F T C A L C U L A T I O N C O D E
527 ************************************************************/
529 static void mk_1shift_tric(int npbcdim,
537 /* Calculate periodicity for triclinic box... */
541 rvec_sub(xi, xj, dx);
544 for (m = npbcdim - 1; (m >= 0); m--)
546 /* If dx < hbox, then xj will be reduced by box, so that
547 * xi - xj will be bigger
549 if (dx[m] < -hbox[m])
552 for (d = m - 1; d >= 0; d--)
557 else if (dx[m] >= hbox[m])
560 for (d = m - 1; d >= 0; d--)
572 static void mk_1shift(int npbcdim, const rvec hbox, const rvec xi, const rvec xj, const int* mi, int* mj)
574 /* Calculate periodicity for rectangular box... */
578 rvec_sub(xi, xj, dx);
581 for (m = 0; (m < npbcdim); m++)
583 /* If dx < hbox, then xj will be reduced by box, so that
584 * xi - xj will be bigger
586 if (dx[m] < -hbox[m])
590 else if (dx[m] >= hbox[m])
601 static void mk_1shift_screw(const matrix box, const rvec hbox, const rvec xi, const rvec xj, const int* mi, int* mj)
603 /* Calculate periodicity for rectangular box... */
607 if ((mi[XX] > 0 && mi[XX] % 2 == 1) || (mi[XX] < 0 && -mi[XX] % 2 == 1))
616 rvec_sub(xi, xj, dx);
618 if (dx[XX] < -hbox[XX])
622 else if (dx[XX] >= hbox[XX])
630 if (mj[XX] != mi[XX])
633 dx[YY] = xi[YY] - (box[YY][YY] + box[ZZ][YY] - xj[YY]);
634 dx[ZZ] = xi[ZZ] - (box[ZZ][ZZ] - xj[ZZ]);
636 for (m = 1; (m < DIM); m++)
638 /* The signs are taken such that we can first shift x and rotate
639 * and then shift y and z.
641 if (dx[m] < -hbox[m])
643 mj[m] = mi[m] - signi;
645 else if (dx[m] >= hbox[m])
647 mj[m] = mi[m] + signi;
656 static int mk_grey(egCol egc[], t_graph* g, int* AtomI, int npbcdim, const matrix box, const rvec x[], int* nerror)
658 int m, j, ng, ai, aj, g0;
664 for (m = 0; (m < DIM); m++)
666 hbox[m] = box[m][m] * 0.5;
668 bTriclinic = TRICLINIC(box);
674 /* Loop over all the bonds */
675 for (j = 0; (j < g->nedge[ai - g0]); j++)
677 aj = g->edge[ai - g0][j];
678 /* If there is a white one, make it grey and set pbc */
681 mk_1shift_screw(box, hbox, x[ai], x[aj], g->ishift[ai], is_aj);
685 mk_1shift_tric(npbcdim, box, hbox, x[ai], x[aj], g->ishift[ai], is_aj);
689 mk_1shift(npbcdim, hbox, x[ai], x[aj], g->ishift[ai], is_aj);
692 if (egc[aj - g0] == egcolWhite)
694 if (aj - g0 < *AtomI)
698 egc[aj - g0] = egcolGrey;
700 copy_ivec(is_aj, g->ishift[aj]);
704 else if ((is_aj[XX] != g->ishift[aj][XX]) || (is_aj[YY] != g->ishift[aj][YY])
705 || (is_aj[ZZ] != g->ishift[aj][ZZ]))
709 set_pbc(&pbc, PbcType::Unset, box);
710 pbc_dx(&pbc, x[ai], x[aj], dx);
712 "mk_grey: shifts for atom %d due to atom %d\n"
713 "are (%d,%d,%d), should be (%d,%d,%d)\n"
715 aj + 1, ai + 1, is_aj[XX], is_aj[YY], is_aj[ZZ], g->ishift[aj][XX],
716 g->ishift[aj][YY], g->ishift[aj][ZZ], dx[XX], dx[YY], dx[ZZ]);
724 static int first_colour(int fC, egCol Col, t_graph* g, const egCol egc[])
725 /* Return the first node with colour Col starting at fC.
726 * return -1 if none found.
731 for (i = fC; (i < g->nnodes); i++)
733 if ((g->nedge[i] > 0) && (egc[i] == Col))
742 /* Returns the maximum length of the graph edges for coordinates x */
743 static real maxEdgeLength(const t_graph g, PbcType pbcType, const matrix box, const rvec x[])
747 set_pbc(&pbc, pbcType, box);
749 real maxEdgeLength2 = 0;
751 for (int node = 0; node < g.nnodes; node++)
753 for (int edge = 0; edge < g.nedge[node]; edge++)
755 int nodeJ = g.edge[node][edge];
757 pbc_dx(&pbc, x[g.at0 + node], x[g.at0 + nodeJ], dx);
758 maxEdgeLength2 = std::max(maxEdgeLength2, norm2(dx));
762 return std::sqrt(maxEdgeLength2);
765 void mk_mshift(FILE* log, t_graph* g, PbcType pbcType, const matrix box, const rvec x[])
767 static int nerror_tot = 0;
770 int nW, nG, nB; /* Number of Grey, Black, White */
771 int fW, fG; /* First of each category */
774 g->bScrewPBC = (pbcType == PbcType::Screw);
776 if (pbcType == PbcType::XY)
786 /* This puts everything in the central box, that is does not move it
787 * at all. If we return without doing this for a system without bonds
788 * (i.e. only settles) all water molecules are moved to the opposite octant
790 for (i = g->at0; (i < g->at1); i++)
792 g->ishift[i][XX] = g->ishift[i][YY] = g->ishift[i][ZZ] = 0;
801 if (nnodes > g->negc)
804 srenew(g->egc, g->negc);
806 memset(g->egc, 0, static_cast<size_t>(nnodes * sizeof(g->egc[0])));
814 /* We even have a loop invariant:
815 * nW+nG+nB == g->nbound
818 fprintf(log, "Starting W loop\n");
822 /* Find the first white, this will allways be a larger
823 * number than before, because no nodes are made white
826 if ((fW = first_colour(fW, egcolWhite, g, g->egc)) == -1)
828 gmx_fatal(FARGS, "No WHITE nodes found while nW=%d\n", nW);
831 /* Make the first white node grey */
832 g->egc[fW] = egcolGrey;
836 /* Initial value for the first grey */
839 fprintf(log, "Starting G loop (nW=%d, nG=%d, nB=%d, total %d)\n", nW, nG, nB, nW + nG + nB);
843 if ((fG = first_colour(fG, egcolGrey, g, g->egc)) == -1)
845 gmx_fatal(FARGS, "No GREY nodes found while nG=%d\n", nG);
848 /* Make the first grey node black */
849 g->egc[fG] = egcolBlack;
853 /* Make all the neighbours of this black node grey
854 * and set their periodicity
856 ng = mk_grey(g->egc, g, &fG, npbcdim, box, x, &nerror);
857 /* ng is the number of white nodes made grey */
864 /* We use a threshold of 0.25*boxSize for generating a fatal error
865 * to allow removing PBC for systems with periodic molecules.
867 * TODO: Consider a better solution for systems with periodic
868 * molecules. Ideally analysis tools should only ask to make
869 * non-periodic molecules whole in a system with periodic mols.
871 constexpr real c_relativeDistanceThreshold = 0.25;
873 int npbcdim = numPbcDimensions(pbcType);
874 GMX_RELEASE_ASSERT(npbcdim > 0, "Expect PBC with graph");
875 real minBoxSize = norm(box[XX]);
876 for (int d = 1; d < npbcdim; d++)
878 minBoxSize = std::min(minBoxSize, norm(box[d]));
880 real maxDistance = maxEdgeLength(*g, pbcType, box, x);
881 if (maxDistance >= c_relativeDistanceThreshold * minBoxSize)
883 std::string mesg = gmx::formatString(
884 "There are inconsistent shifts over periodic boundaries in a molecule type "
885 "consisting of %d atoms. The longest distance involved in such interactions is "
886 "%.3f nm which is %s half the box length.",
887 g->at1 - g->at0, maxDistance, maxDistance >= 0.5 * minBoxSize ? "above" : "close to");
891 case t_graph::BondedParts::MultipleConnected:
892 /* Ideally we should check if the long distances are
893 * actually between the parts, but that would require
894 * a lot of extra code.
896 mesg += " This molecule type consists of muliple parts, e.g. monomers, that "
897 "are connected by interactions that are not chemical bonds, e.g. "
898 "restraints. Such systems can not be treated. The only solution is "
899 "increasing the box size.";
902 mesg += " Either you have excessively large distances between atoms in bonded "
903 "interactions or your system is exploding.";
905 gmx_fatal(FARGS, "%s", mesg.c_str());
908 /* The most likely reason for arriving here is a periodic molecule. */
911 if (nerror_tot <= 100)
913 fprintf(stderr, "There were %d inconsistent shifts. Check your topology\n", nerror);
916 fprintf(log, "There were %d inconsistent shifts. Check your topology\n", nerror);
919 if (nerror_tot == 100)
921 fprintf(stderr, "Will stop reporting inconsistent shifts\n");
924 fprintf(log, "Will stop reporting inconsistent shifts\n");
930 /************************************************************
932 * A C T U A L S H I F T C O D E
934 ************************************************************/
936 void shift_x(const t_graph* g, const matrix box, const rvec x[], rvec x_s[])
947 for (j = g->at0; j < g0; j++)
949 copy_rvec(x[j], x_s[j]);
954 for (j = g0; (j < g1); j++)
960 if ((tx > 0 && tx % 2 == 1) || (tx < 0 && -tx % 2 == 1))
962 x_s[j][XX] = x[j][XX] + tx * box[XX][XX];
963 x_s[j][YY] = box[YY][YY] + box[ZZ][YY] - x[j][YY];
964 x_s[j][ZZ] = box[ZZ][ZZ] - x[j][ZZ];
968 x_s[j][XX] = x[j][XX];
970 x_s[j][YY] = x[j][YY] + ty * box[YY][YY] + tz * box[ZZ][YY];
971 x_s[j][ZZ] = x[j][ZZ] + tz * box[ZZ][ZZ];
974 else if (TRICLINIC(box))
976 for (j = g0; (j < g1); j++)
982 x_s[j][XX] = x[j][XX] + tx * box[XX][XX] + ty * box[YY][XX] + tz * box[ZZ][XX];
983 x_s[j][YY] = x[j][YY] + ty * box[YY][YY] + tz * box[ZZ][YY];
984 x_s[j][ZZ] = x[j][ZZ] + tz * box[ZZ][ZZ];
989 for (j = g0; (j < g1); j++)
995 x_s[j][XX] = x[j][XX] + tx * box[XX][XX];
996 x_s[j][YY] = x[j][YY] + ty * box[YY][YY];
997 x_s[j][ZZ] = x[j][ZZ] + tz * box[ZZ][ZZ];
1001 for (j = g1; j < g->at1; j++)
1003 copy_rvec(x[j], x_s[j]);
1007 void shift_self(const t_graph* g, const matrix box, rvec x[])
1015 gmx_incons("screw pbc not implemented for shift_self");
1023 fprintf(stderr, "Shifting atoms %d to %d\n", g0, g0 + gn);
1027 for (j = g0; (j < g1); j++)
1033 x[j][XX] = x[j][XX] + tx * box[XX][XX] + ty * box[YY][XX] + tz * box[ZZ][XX];
1034 x[j][YY] = x[j][YY] + ty * box[YY][YY] + tz * box[ZZ][YY];
1035 x[j][ZZ] = x[j][ZZ] + tz * box[ZZ][ZZ];
1040 for (j = g0; (j < g1); j++)
1046 x[j][XX] = x[j][XX] + tx * box[XX][XX];
1047 x[j][YY] = x[j][YY] + ty * box[YY][YY];
1048 x[j][ZZ] = x[j][ZZ] + tz * box[ZZ][ZZ];
1053 void unshift_x(const t_graph* g, const matrix box, rvec x[], const rvec x_s[])
1061 gmx_incons("screw pbc not implemented (yet) for unshift_x");
1068 for (j = g->at0; j < g0; j++)
1070 copy_rvec(x_s[j], x[j]);
1075 for (j = g0; (j < g1); j++)
1081 x[j][XX] = x_s[j][XX] - tx * box[XX][XX] - ty * box[YY][XX] - tz * box[ZZ][XX];
1082 x[j][YY] = x_s[j][YY] - ty * box[YY][YY] - tz * box[ZZ][YY];
1083 x[j][ZZ] = x_s[j][ZZ] - tz * box[ZZ][ZZ];
1088 for (j = g0; (j < g1); j++)
1094 x[j][XX] = x_s[j][XX] - tx * box[XX][XX];
1095 x[j][YY] = x_s[j][YY] - ty * box[YY][YY];
1096 x[j][ZZ] = x_s[j][ZZ] - tz * box[ZZ][ZZ];
1100 for (j = g1; j < g->at1; j++)
1102 copy_rvec(x_s[j], x[j]);
1106 void unshift_self(const t_graph* g, const matrix box, rvec x[])
1114 gmx_incons("screw pbc not implemented for unshift_self");
1123 for (j = g0; (j < g1); j++)
1129 x[j][XX] = x[j][XX] - tx * box[XX][XX] - ty * box[YY][XX] - tz * box[ZZ][XX];
1130 x[j][YY] = x[j][YY] - ty * box[YY][YY] - tz * box[ZZ][YY];
1131 x[j][ZZ] = x[j][ZZ] - tz * box[ZZ][ZZ];
1136 for (j = g0; (j < g1); j++)
1142 x[j][XX] = x[j][XX] - tx * box[XX][XX];
1143 x[j][YY] = x[j][YY] - ty * box[YY][YY];
1144 x[j][ZZ] = x[j][ZZ] - tz * box[ZZ][ZZ];