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.
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
)
74 inda0
= a0
- g
->at_start
;
75 inda1
= a1
- g
->at_start
;
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
);
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.
98 static bool mk_igraph(t_graph
*g
, int ftype
, const T
&il
,
99 int at_start
, int at_end
,
104 bool addedEdge
= false;
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
)
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.",
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]);
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]);
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]);
161 [[noreturn
]] static void g_error(int line
, const char *file
)
163 gmx_fatal(FARGS
, "Trying to print nonexistent graph (file %s, line %d)",
166 #define GCHECK(g) if ((g) == NULL) 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,
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
]] : " ",
190 for (j
= 0; (j
< g
->nedge
[i
]); j
++)
192 fprintf(log
, " %5d", g
->edge
[i
][j
]+1);
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
;
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
)
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);
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
)
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
,
258 g
->at_start
= at_end
;
261 /* First add all the real bonds: they should determine the molecular
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
);
284 for (i
= g
->at_start
; (i
< g
->at_end
); i
++)
287 nnb
= std::max(nnb
, nbond
[i
]);
291 fprintf(fplog
, "Max number of connections per atom is %d\n", nnb
);
292 fprintf(fplog
, "Total number of connections is %d\n", nbtot
);
299 static void compact_graph(FILE *fplog
, t_graph
*g
)
301 int i
, j
, n
, max_nedge
;
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];
322 fprintf(fplog
, "Max number of graph edges per atom is %d\n",
324 fprintf(fplog
, "Total number of graph edges is %d\n", n
);
328 static gmx_bool
determine_graph_parts(t_graph
*g
, int *part
)
335 /* Initialize the part array with all entries different */
336 for (at_i
= g
->at_start
; at_i
< g
->at_end
; at_i
++)
341 /* Loop over the graph until the part array is fixed */
346 for (i
= 0; (i
< g
->nnodes
); i
++)
348 at_i
= g
->at_start
+ 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
];
358 else if (part
[at_i2
[e
]] < part
[at_i
])
360 part
[at_i
] = part
[at_i2
[e
]];
364 if (part
[at_i
] != part
[g
->at_start
])
371 fprintf(debug
, "graph part[] nchanged=%d, bMultiPart=%s\n",
372 nchanged
, gmx::boolToString(bMultiPart
));
375 while (nchanged
> 0);
380 template <typename T
>
382 mk_graph_ilist(FILE *fplog
,
383 const T
*ilist
, int at_start
, int at_end
,
384 gmx_bool bShakeOnly
, gmx_bool bSettle
,
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).
398 g
->parts
= t_graph::BondedParts::Single
;
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
;
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];
424 /* First add all the real bonds: they should determine the molecular
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
);
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
);
459 g
->parts
= t_graph::BondedParts::MultipleConnected
;
463 g
->parts
= t_graph::BondedParts::MultipleDisconnected
;
467 /* Removed all the unused space from the edge array */
468 compact_graph(fplog
, g
);
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);
476 mk_igraph(g
, F_SETTLE
, ilist
[F_SETTLE
], at_start
, at_end
, nullptr);
480 for (i
= 0; (i
< g
->nnodes
); i
++)
494 snew(g
->ishift
, g
->at1
);
498 p_graph(debug
, "graph", g
);
502 void mk_graph_moltype(const gmx_moltype_t
&moltype
,
505 mk_graph_ilist(nullptr, moltype
.ilist
.data(), 0, moltype
.atoms
.nr
,
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
)
518 mk_graph_ilist(fplog
, idef
->il
, at_start
, at_end
, bShakeOnly
, bSettle
, g
);
523 void done_graph(t_graph
*g
)
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... */
549 rvec_sub(xi
, xj
, dx
);
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
])
560 for (d
= m
-1; d
>= 0; d
--)
565 else if (dx
[m
] >= hbox
[m
])
568 for (d
= m
-1; d
>= 0; d
--)
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... */
587 rvec_sub(xi
, xj
, dx
);
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
])
599 else if (dx
[m
] >= hbox
[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... */
617 if ((mi
[XX
] > 0 && mi
[XX
] % 2 == 1) ||
618 (mi
[XX
] < 0 && -mi
[XX
] % 2 == 1))
627 rvec_sub(xi
, xj
, dx
);
629 if (dx
[XX
] < -hbox
[XX
])
633 else if (dx
[XX
] >= hbox
[XX
])
641 if (mj
[XX
] != mi
[XX
])
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
;
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
;
676 for (m
= 0; (m
< DIM
); m
++)
678 hbox
[m
] = box
[m
][m
]*0.5;
680 bTriclinic
= TRICLINIC(box
);
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 */
693 mk_1shift_screw(box
, hbox
, x
[ai
], x
[aj
], g
->ishift
[ai
], is_aj
);
697 mk_1shift_tric(npbcdim
, box
, hbox
, x
[ai
], x
[aj
], g
->ishift
[ai
], is_aj
);
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
)
710 egc
[aj
-g0
] = egcolGrey
;
712 copy_ivec(is_aj
, g
->ishift
[aj
]);
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
]))
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"
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
]);
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.
744 for (i
= fC
; (i
< g
->nnodes
); i
++)
746 if ((g
->nedge
[i
] > 0) && (egc
[i
] == Col
))
755 /* Returns the maximum length of the graph edges for coordinates x */
756 static real
maxEdgeLength(const t_graph g
,
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
];
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;
787 int nW
, nG
, nB
; /* Number of Grey, Black, White */
788 int fW
, fG
; /* First of each category */
791 g
->bScrewPBC
= (ePBC
== epbcSCREW
);
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;
818 if (nnodes
> g
->negc
)
821 srenew(g
->egc
, g
->negc
);
823 memset(g
->egc
, 0, static_cast<size_t>(nnodes
*sizeof(g
->egc
[0])));
831 /* We even have a loop invariant:
832 * nW+nG+nB == g->nbound
835 fprintf(log
, "Starting W loop\n");
839 /* Find the first white, this will allways be a larger
840 * number than before, because no nodes are made white
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
;
853 /* Initial value for the first grey */
856 fprintf(log
, "Starting G loop (nW=%d, nG=%d, nB=%d, total %d)\n",
857 nW
, nG
, nB
, nW
+nG
+nB
);
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
;
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 */
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");
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.";
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. */
923 if (nerror_tot
<= 100)
925 fprintf(stderr
, "There were %d inconsistent shifts. Check your topology\n",
929 fprintf(log
, "There were %d inconsistent shifts. Check your topology\n",
933 if (nerror_tot
== 100)
935 fprintf(stderr
, "Will stop reporting inconsistent shifts\n");
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
[])
961 for (j
= g
->at0
; j
< g0
; j
++)
963 copy_rvec(x
[j
], x_s
[j
]);
968 for (j
= g0
; (j
< g1
); j
++)
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
];
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
++)
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
];
1004 for (j
= g0
; (j
< g1
); j
++)
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
[])
1030 gmx_incons("screw pbc not implemented for shift_self");
1038 fprintf(stderr
, "Shifting atoms %d to %d\n", g0
, g0
+gn
);
1042 for (j
= g0
; (j
< g1
); j
++)
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
];
1055 for (j
= g0
; (j
< g1
); j
++)
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
[])
1076 gmx_incons("screw pbc not implemented (yet) for unshift_x");
1083 for (j
= g
->at0
; j
< g0
; j
++)
1085 copy_rvec(x_s
[j
], x
[j
]);
1090 for (j
= g0
; (j
< g1
); j
++)
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
];
1103 for (j
= g0
; (j
< g1
); j
++)
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
[])
1129 gmx_incons("screw pbc not implemented for unshift_self");
1138 for (j
= g0
; (j
< g1
); j
++)
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
];
1151 for (j
= g0
; (j
< g1
); j
++)
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
];