3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * GROningen Mixture of Alchemy and Childrens' Stories
41 #include "gmx_fatal.h"
50 /************************************************************
52 * S H I F T U T I L I T I E S
54 ************************************************************/
57 /************************************************************
59 * G R A P H G E N E R A T I O N C O D E
61 ************************************************************/
63 static void add_gbond(t_graph
*g
,atom_id a0
,atom_id a1
)
69 inda0
= a0
- g
->start
;
70 inda1
= a1
- g
->start
;
72 /* Search for a direct edge between a0 and a1.
73 * All egdes are bidirectional, so we only need to search one way.
75 for(i
=0; (i
<g
->nedge
[inda0
] && !bFound
); i
++) {
76 bFound
= (g
->edge
[inda0
][i
] == a1
);
80 g
->edge
[inda0
][g
->nedge
[inda0
]++] = a1
;
81 g
->edge
[inda1
][g
->nedge
[inda1
]++] = a0
;
85 static void mk_igraph(t_graph
*g
,int ftype
,t_ilist
*il
,
86 int at_start
,int at_end
,
98 np
= interaction_function
[ftype
].nratoms
;
100 if (ia
[1] >= at_start
&& ia
[1] < at_end
) {
101 if (ia
[np
] >= at_end
)
103 "Molecule in topology has atom numbers below and "
104 "above natoms (%d).\n"
105 "You are probably trying to use a trajectory which does "
106 "not match the first %d atoms of the run input file.\n"
107 "You can make a matching run input file with tpbconv.",
109 if (ftype
== F_SETTLE
) {
110 /* Bond all the atoms in the settle */
111 add_gbond(g
,ia
[1],ia
[1]+1);
112 add_gbond(g
,ia
[1],ia
[1]+2);
113 } else if (part
== NULL
) {
114 /* Simply add this bond */
115 for(j
=1; j
<np
; j
++) {
116 add_gbond(g
,ia
[j
],ia
[j
+1]);
119 /* Add this bond when it connects two unlinked parts of the graph */
120 for(j
=1; j
<np
; j
++) {
121 if (part
[ia
[j
]] != part
[ia
[j
+1]]) {
122 add_gbond(g
,ia
[j
],ia
[j
+1]);
132 static void g_error(int line
,const char *file
)
134 gmx_fatal(FARGS
,"Tring to print non existant graph (file %s, line %d)",
137 #define GCHECK(g) if (g == NULL) g_error(__LINE__,__FILE__)
139 void p_graph(FILE *log
,const char *title
,t_graph
*g
)
142 const char *cc
[egcolNR
] = { "W", "G", "B" };
145 fprintf(log
,"graph: %s\n",title
);
146 fprintf(log
,"nnodes: %d\n",g
->nnodes
);
147 fprintf(log
,"nbound: %d\n",g
->nbound
);
148 fprintf(log
,"start: %d\n",g
->start
);
149 fprintf(log
,"end: %d\n",g
->end
);
150 fprintf(log
," atom shiftx shifty shiftz C nedg e1 e2 etc.\n");
151 for(i
=0; (i
<g
->nnodes
); i
++)
152 if (g
->nedge
[i
] > 0) {
153 fprintf(log
,"%5d%7d%7d%7d %1s%5d",g
->start
+i
+1,
154 g
->ishift
[i
][XX
],g
->ishift
[i
][YY
],
156 (g
->negc
> 0) ? cc
[g
->egc
[i
]] : " ",
158 for(j
=0; (j
<g
->nedge
[i
]); j
++)
159 fprintf(log
," %5u",g
->edge
[i
][j
]+1);
165 static void calc_1se(t_graph
*g
,int ftype
,t_ilist
*il
,
166 int nbond
[],int at_start
,int at_end
)
174 for(j
=0; (j
<end
); j
+=nratoms
+1,ia
+=nratoms
+1) {
175 nratoms
= interaction_function
[ftype
].nratoms
;
177 if (ftype
== F_SETTLE
) {
179 if (iaa
>= at_start
&& iaa
< at_end
) {
183 g
->start
= min(g
->start
,iaa
);
184 g
->end
= max(g
->end
,iaa
+2);
187 for(k
=1; (k
<=nratoms
); k
++) {
189 if (iaa
>= at_start
&& iaa
< at_end
) {
190 g
->start
=min(g
->start
,iaa
);
191 g
->end
=max(g
->end
, iaa
);
192 /* When making the graph we (might) link all atoms in an interaction
193 * sequentially. Therefore the end atoms add 1 to the count,
194 * the middle atoms 2.
196 if (k
== 1 || k
== nratoms
) {
207 static int calc_start_end(FILE *fplog
,t_graph
*g
,t_ilist il
[],
208 int at_start
,int at_end
,
216 /* First add all the real bonds: they should determine the molecular
219 for(i
=0; (i
<F_NRE
); i
++)
220 if (interaction_function
[i
].flags
& IF_CHEMBOND
)
221 calc_1se(g
,i
,&il
[i
],nbond
,at_start
,at_end
);
222 /* Then add all the other interactions in fixed lists, but first
223 * check to see what's there already.
225 for(i
=0; (i
<F_NRE
); i
++) {
226 if (!(interaction_function
[i
].flags
& IF_CHEMBOND
)) {
227 calc_1se(g
,i
,&il
[i
],nbond
,at_start
,at_end
);
233 for(i
=g
->start
; (i
<=g
->end
); i
++) {
235 nnb
= max(nnb
,nbond
[i
]);
238 fprintf(fplog
,"Max number of connections per atom is %d\n",nnb
);
239 fprintf(fplog
,"Total number of connections is %d\n",nbtot
);
246 static void compact_graph(FILE *fplog
,t_graph
*g
)
253 for(i
=0; i
<g
->nnodes
; i
++) {
254 for(j
=0; j
<g
->nedge
[i
]; j
++) {
255 g
->edge
[0][n
++] = g
->edge
[i
][j
];
257 g
->edge
[i
] = g
->edge
[0] + n
- g
->nedge
[i
];
258 max_nedge
= max(max_nedge
,g
->nedge
[i
]);
260 srenew(g
->edge
[0],n
);
263 fprintf(fplog
,"Max number of graph edges per atom is %d\n",
265 fprintf(fplog
,"Total number of graph edges is %d\n",n
);
269 static bool determine_graph_parts(t_graph
*g
,int *part
)
276 /* Initialize the part array with all entries different */
277 for(at_i
=g
->start
; at_i
<g
->end
; at_i
++) {
281 /* Loop over the graph until the part array is fixed */
285 for(i
=0; (i
<g
->nnodes
); i
++) {
288 for(e
=0; e
<g
->nedge
[i
]; e
++) {
289 /* Set part for both nodes to the minimum */
290 if (part
[at_i2
[e
]] > part
[at_i
]) {
291 part
[at_i2
[e
]] = part
[at_i
];
293 } else if (part
[at_i2
[e
]] < part
[at_i
]) {
294 part
[at_i
] = part
[at_i2
[e
]];
298 if (part
[at_i
] != part
[g
->start
]) {
303 fprintf(debug
,"graph part[] nchanged=%d, bMultiPart=%d\n",
304 nchanged
,bMultiPart
);
306 } while (nchanged
> 0);
311 void mk_graph_ilist(FILE *fplog
,
312 t_ilist
*ilist
,int at_start
,int at_end
,
313 bool bShakeOnly
,bool bSettle
,
321 nbtot
= calc_start_end(fplog
,g
,ilist
,at_start
,at_end
,nbond
);
323 if (g
->start
>= g
->end
) {
328 g
->nnodes
= g
->end
- g
->start
+ 1;
329 snew(g
->ishift
,g
->nnodes
);
330 snew(g
->nedge
,g
->nnodes
);
331 snew(g
->edge
,g
->nnodes
);
332 /* Allocate a single array and set pointers into it */
333 snew(g
->edge
[0],nbtot
);
334 for(i
=1; (i
<g
->nnodes
); i
++) {
335 g
->edge
[i
] = g
->edge
[i
-1] + nbond
[g
->start
+i
-1];
339 /* First add all the real bonds: they should determine the molecular
342 for(i
=0; (i
<F_NRE
); i
++)
343 if (interaction_function
[i
].flags
& IF_CHEMBOND
)
344 mk_igraph(g
,i
,&(ilist
[i
]),at_start
,at_end
,NULL
);
346 /* Determine of which separated parts the IF_CHEMBOND graph consists.
347 * Store the parts in the nbond array.
349 bMultiPart
= determine_graph_parts(g
,nbond
);
352 /* Then add all the other interactions in fixed lists,
353 * but only when they connect parts of the graph
354 * that are not connected through IF_CHEMBOND interactions.
356 for(i
=0; (i
<F_NRE
); i
++) {
357 if (!(interaction_function
[i
].flags
& IF_CHEMBOND
)) {
358 mk_igraph(g
,i
,&(ilist
[i
]),at_start
,at_end
,nbond
);
363 /* Removed all the unused space from the edge array */
364 compact_graph(fplog
,g
);
367 /* This is a special thing used in splitter.c to generate shake-blocks */
368 mk_igraph(g
,F_CONSTR
,&(ilist
[F_CONSTR
]),at_start
,at_end
,NULL
);
370 mk_igraph(g
,F_SETTLE
,&(ilist
[F_SETTLE
]),at_start
,at_end
,NULL
);
373 for(i
=0; (i
<g
->nnodes
); i
++)
384 p_graph(debug
,"graph",g
);
387 t_graph
*mk_graph(FILE *fplog
,
388 t_idef
*idef
,int at_start
,int at_end
,
389 bool bShakeOnly
,bool bSettle
)
395 mk_graph_ilist(fplog
,idef
->il
,at_start
,at_end
,bShakeOnly
,bSettle
,g
);
400 void done_graph(t_graph
*g
)
414 /************************************************************
416 * S H I F T C A L C U L A T I O N C O D E
418 ************************************************************/
420 static void mk_1shift_tric(int npbcdim
,matrix box
,rvec hbox
,
421 rvec xi
,rvec xj
,int *mi
,int *mj
)
423 /* Calculate periodicity for triclinic box... */
430 for(m
=npbcdim
-1; (m
>=0); m
--) {
431 /* If dx < hbox, then xj will be reduced by box, so that
432 * xi - xj will be bigger
434 if (dx
[m
] < -hbox
[m
]) {
436 for(d
=m
-1; d
>=0; d
--)
438 } else if (dx
[m
] >= hbox
[m
]) {
440 for(d
=m
-1; d
>=0; d
--)
447 static void mk_1shift(int npbcdim
,rvec hbox
,rvec xi
,rvec xj
,int *mi
,int *mj
)
449 /* Calculate periodicity for rectangular box... */
456 for(m
=0; (m
<npbcdim
); m
++) {
457 /* If dx < hbox, then xj will be reduced by box, so that
458 * xi - xj will be bigger
460 if (dx
[m
] < -hbox
[m
])
462 else if (dx
[m
] >= hbox
[m
])
469 static void mk_1shift_screw(matrix box
,rvec hbox
,
470 rvec xi
,rvec xj
,int *mi
,int *mj
)
472 /* Calculate periodicity for rectangular box... */
476 if ((mi
[XX
] > 0 && mi
[XX
] % 2 == 1) ||
477 (mi
[XX
] < 0 && -mi
[XX
] % 2 == 1)) {
485 if (dx
[XX
] < -hbox
[XX
])
487 else if (dx
[XX
] >= hbox
[XX
])
491 if (mj
[XX
] != mi
[XX
]) {
493 dx
[YY
] = xi
[YY
] - (box
[YY
][YY
] + box
[ZZ
][YY
] - xj
[YY
]);
494 dx
[ZZ
] = xi
[ZZ
] - (box
[ZZ
][ZZ
] - xj
[ZZ
]);
496 for(m
=1; (m
<DIM
); m
++) {
497 /* The signs are taken such that we can first shift x and rotate
498 * and then shift y and z.
500 if (dx
[m
] < -hbox
[m
])
501 mj
[m
] = mi
[m
] - signi
;
502 else if (dx
[m
] >= hbox
[m
])
503 mj
[m
] = mi
[m
] + signi
;
509 static int mk_grey(FILE *log
,int nnodes
,egCol egc
[],t_graph
*g
,int *AtomI
,
510 int npbcdim
,matrix box
,rvec x
[],int *nerror
)
518 for(m
=0; (m
<DIM
); m
++)
519 hbox
[m
]=box
[m
][m
]*0.5;
520 bTriclinic
= TRICLINIC(box
);
526 /* Loop over all the bonds */
527 for(j
=0; (j
<g
->nedge
[ai
]); j
++) {
528 aj
=g
->edge
[ai
][j
]-g0
;
529 /* If there is a white one, make it grey and set pbc */
531 mk_1shift_screw(box
,hbox
,x
[g0
+ai
],x
[g0
+aj
],g
->ishift
[ai
],is_aj
);
533 mk_1shift_tric(npbcdim
,box
,hbox
,x
[g0
+ai
],x
[g0
+aj
],g
->ishift
[ai
],is_aj
);
535 mk_1shift(npbcdim
,hbox
,x
[g0
+ai
],x
[g0
+aj
],g
->ishift
[ai
],is_aj
);
537 if (egc
[aj
] == egcolWhite
) {
542 copy_ivec(is_aj
,g
->ishift
[aj
]);
546 else if ((is_aj
[XX
] != g
->ishift
[aj
][XX
]) ||
547 (is_aj
[YY
] != g
->ishift
[aj
][YY
]) ||
548 (is_aj
[ZZ
] != g
->ishift
[aj
][ZZ
])) {
550 set_pbc(&pbc
,-1,box
);
551 pbc_dx(&pbc
,x
[g0
+ai
],x
[g0
+aj
],dx
);
552 fprintf(debug
,"mk_grey: shifts for atom %d due to atom %d\n"
553 "are (%d,%d,%d), should be (%d,%d,%d)\n"
555 aj
+g0
+1,ai
+g0
+1,is_aj
[XX
],is_aj
[YY
],is_aj
[ZZ
],
556 g
->ishift
[aj
][XX
],g
->ishift
[aj
][YY
],g
->ishift
[aj
][ZZ
],
557 dx
[XX
],dx
[YY
],dx
[ZZ
]);
565 static int first_colour(int fC
,egCol Col
,t_graph
*g
,egCol egc
[])
566 /* Return the first node with colour Col starting at fC.
567 * return -1 if none found.
572 for(i
=fC
; (i
<g
->nnodes
); i
++)
573 if ((g
->nedge
[i
] > 0) && (egc
[i
]==Col
))
579 void mk_mshift(FILE *log
,t_graph
*g
,int ePBC
,matrix box
,rvec x
[])
581 static int nerror_tot
= 0;
584 int nW
,nG
,nB
; /* Number of Grey, Black, White */
585 int fW
,fG
; /* First of each category */
588 g
->bScrewPBC
= (ePBC
== epbcSCREW
);
596 /* This puts everything in the central box, that is does not move it
597 * at all. If we return without doing this for a system without bonds
598 * (i.e. only settles) all water molecules are moved to the opposite octant
600 for(i
=0; (i
<g
->nnodes
); i
++) {
601 g
->ishift
[i
][XX
]=g
->ishift
[i
][YY
]=g
->ishift
[i
][ZZ
]=0;
608 if (nnodes
> g
->negc
) {
610 srenew(g
->egc
,g
->negc
);
612 memset(g
->egc
,0,(size_t)(nnodes
*sizeof(g
->egc
[0])));
620 /* We even have a loop invariant:
621 * nW+nG+nB == g->nbound
624 fprintf(log
,"Starting W loop\n");
627 /* Find the first white, this will allways be a larger
628 * number than before, because no nodes are made white
631 if ((fW
=first_colour(fW
,egcolWhite
,g
,g
->egc
)) == -1)
632 gmx_fatal(FARGS
,"No WHITE nodes found while nW=%d\n",nW
);
634 /* Make the first white node grey */
635 g
->egc
[fW
]=egcolGrey
;
639 /* Initial value for the first grey */
642 fprintf(log
,"Starting G loop (nW=%d, nG=%d, nB=%d, total %d)\n",
646 if ((fG
=first_colour(fG
,egcolGrey
,g
,g
->egc
)) == -1)
647 gmx_fatal(FARGS
,"No GREY nodes found while nG=%d\n",nG
);
649 /* Make the first grey node black */
650 g
->egc
[fG
]=egcolBlack
;
654 /* Make all the neighbours of this black node grey
655 * and set their periodicity
657 ng
=mk_grey(log
,nnodes
,g
->egc
,g
,&fG
,npbcdim
,box
,x
,&nerror
);
658 /* ng is the number of white nodes made grey */
665 if (nerror_tot
<= 100) {
666 fprintf(stderr
,"There were %d inconsistent shifts. Check your topology\n",
669 fprintf(log
,"There were %d inconsistent shifts. Check your topology\n",
673 if (nerror_tot
== 100) {
674 fprintf(stderr
,"Will stop reporting inconsistent shifts\n");
676 fprintf(log
,"Will stop reporting inconsistent shifts\n");
682 /************************************************************
684 * A C T U A L S H I F T C O D E
686 ************************************************************/
688 void shift_x(t_graph
*g
,matrix box
,rvec x
[],rvec x_s
[])
700 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
705 if ((tx
> 0 && tx
% 2 == 1) ||
706 (tx
< 0 && -tx
%2 == 1)) {
707 x_s
[j
][XX
] = x
[j
][XX
] + tx
*box
[XX
][XX
];
708 x_s
[j
][YY
] = box
[YY
][YY
] + box
[ZZ
][YY
] - x
[j
][YY
];
709 x_s
[j
][ZZ
] = box
[ZZ
][ZZ
] - x
[j
][ZZ
];
711 x_s
[j
][XX
] = x
[j
][XX
];
713 x_s
[j
][YY
] = x
[j
][YY
] + ty
*box
[YY
][YY
] + tz
*box
[ZZ
][YY
];
714 x_s
[j
][ZZ
] = x
[j
][ZZ
] + tz
*box
[ZZ
][ZZ
];
716 } else if (TRICLINIC(box
)) {
717 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
722 x_s
[j
][XX
]=x
[j
][XX
]+tx
*box
[XX
][XX
]+ty
*box
[YY
][XX
]+tz
*box
[ZZ
][XX
];
723 x_s
[j
][YY
]=x
[j
][YY
]+ty
*box
[YY
][YY
]+tz
*box
[ZZ
][YY
];
724 x_s
[j
][ZZ
]=x
[j
][ZZ
]+tz
*box
[ZZ
][ZZ
];
727 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
732 x_s
[j
][XX
]=x
[j
][XX
]+tx
*box
[XX
][XX
];
733 x_s
[j
][YY
]=x
[j
][YY
]+ty
*box
[YY
][YY
];
734 x_s
[j
][ZZ
]=x
[j
][ZZ
]+tz
*box
[ZZ
][ZZ
];
740 void shift_self(t_graph
*g
,matrix box
,rvec x
[])
747 gmx_incons("screw pbc not implemented for shift_self");
754 fprintf(stderr
,"Shifting atoms %d to %d\n",g0
,g0
+gn
);
757 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
762 x
[j
][XX
]=x
[j
][XX
]+tx
*box
[XX
][XX
]+ty
*box
[YY
][XX
]+tz
*box
[ZZ
][XX
];
763 x
[j
][YY
]=x
[j
][YY
]+ty
*box
[YY
][YY
]+tz
*box
[ZZ
][YY
];
764 x
[j
][ZZ
]=x
[j
][ZZ
]+tz
*box
[ZZ
][ZZ
];
767 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
772 x
[j
][XX
]=x
[j
][XX
]+tx
*box
[XX
][XX
];
773 x
[j
][YY
]=x
[j
][YY
]+ty
*box
[YY
][YY
];
774 x
[j
][ZZ
]=x
[j
][ZZ
]+tz
*box
[ZZ
][ZZ
];
780 void unshift_x(t_graph
*g
,matrix box
,rvec x
[],rvec x_s
[])
787 gmx_incons("screw pbc not implemented for unshift_x");
793 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
798 x
[j
][XX
]=x_s
[j
][XX
]-tx
*box
[XX
][XX
]-ty
*box
[YY
][XX
]-tz
*box
[ZZ
][XX
];
799 x
[j
][YY
]=x_s
[j
][YY
]-ty
*box
[YY
][YY
]-tz
*box
[ZZ
][YY
];
800 x
[j
][ZZ
]=x_s
[j
][ZZ
]-tz
*box
[ZZ
][ZZ
];
803 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
808 x
[j
][XX
]=x_s
[j
][XX
]-tx
*box
[XX
][XX
];
809 x
[j
][YY
]=x_s
[j
][YY
]-ty
*box
[YY
][YY
];
810 x
[j
][ZZ
]=x_s
[j
][ZZ
]-tz
*box
[ZZ
][ZZ
];
815 void unshift_self(t_graph
*g
,matrix box
,rvec x
[])
822 gmx_incons("screw pbc not implemented for unshift_self");
828 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
833 x
[j
][XX
]=x
[j
][XX
]-tx
*box
[XX
][XX
]-ty
*box
[YY
][XX
]-tz
*box
[ZZ
][XX
];
834 x
[j
][YY
]=x
[j
][YY
]-ty
*box
[YY
][YY
]-tz
*box
[ZZ
][YY
];
835 x
[j
][ZZ
]=x
[j
][ZZ
]-tz
*box
[ZZ
][ZZ
];
838 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
843 x
[j
][XX
]=x
[j
][XX
]-tx
*box
[XX
][XX
];
844 x
[j
][YY
]=x
[j
][YY
]-ty
*box
[YY
][YY
];
845 x
[j
][ZZ
]=x
[j
][ZZ
]-tz
*box
[ZZ
][ZZ
];
852 void main(int argc
,char *argv
[])
866 CopyRight(stderr
,argv
[0]);
867 parse_common_args(&argc
,argv
,&targ
,PCA_NEED_INOUT
,NULL
);
869 pid
=strtol(argv
[1], NULL
, 10);
873 read_status_header(targ
.infile
,&sh
);
875 snew(mshift
,sh
.natoms
);
877 fprintf(stderr
,"Reading Status %s\n",targ
.infile
);
878 read_status(targ
.infile
,&idum
,&rdum
,&rdum
,NULL
,
879 box
,NULL
,NULL
,&idum
,x
,NULL
,NULL
,&idum
,NULL
,&top
);
881 fprintf(stderr
,"Making Graph Structure...\n");
882 g
=mk_graph(&(top
.idef
),top
.atoms
.nr
,FALSE
,FALSE
);
884 out
=gmx_fio_fopen(targ
.outfile
,"w");
886 fprintf(stderr
,"Making Shift...\n");
887 mk_mshift(out
,g
,box
,x
,mshift
);
889 p_graph(out
,"In Den Haag daar woont een graaf...",g
);