4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Copyright (c) 1991-2001, University of Groningen, The Netherlands
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * If you want to redistribute modifications, please consider that
18 * scientific software is very special. Version control is crucial -
19 * bugs must be traceable. We will be happy to consider code for
20 * inclusion in the official distribution, but derived work must not
21 * be called official GROMACS. Details are found in the README & COPYING
22 * files - if they are missing, get the official version at www.gromacs.org.
24 * To help us fund GROMACS development, we humbly ask that you cite
25 * the papers on the package - you can find them in the top README file.
27 * For more info, check our website at http://www.gromacs.org
30 * Gyas ROwers Mature At Cryogenic Speed
45 /************************************************************
47 * S H I F T U T I L I T I E S
49 ************************************************************/
52 /************************************************************
54 * G R A P H G E N E R A T I O N C O D E
56 ************************************************************/
58 static void add_gbond(t_graph
*g
,t_iatom ia
[],int np
)
63 for(j
=0; (j
<np
); j
++) {
68 for(l
=0; (l
<g
->nedge
[inda
]); l
++)
69 if (g
->edge
[inda
][l
] == ia
[k
])
71 if (l
== g
->nedge
[inda
]) {
72 if (g
->nedge
[inda
] == g
->maxedge
)
73 fatal_error(0,"More than %d graph edges per atom (atom %d)\n",
75 g
->edge
[inda
][g
->nedge
[inda
]++]=ia
[k
];
81 static void mk_igraph(t_graph
*g
,t_functype ftype
[],t_ilist
*il
,
84 t_iatom
*ia
,waterh
[3],*iap
;
95 np
=interaction_function
[tp
].nratoms
;
97 if ((ia
[1] < natoms
) && (interaction_function
[tp
].flags
& IF_GRAPH
)) {
99 fatal_error(0,"Molecule in topology has atom numbers below and "
100 "above natoms (%d).\n"
101 "You are probably trying to use a trajectory which does "
102 "not match the first %d atoms of the run input file.\n"
103 "You can make a matching run input file with tpbconv.",
105 if (tp
== F_SETTLE
) {
106 /* Bond all the atoms in the settle */
113 if (interaction_function
[tp
].flags
& IF_DUMMY
)
114 /* Bond a dummy only to the first constructing atom */
121 add_gbond(g
,iap
,nbonded
);
123 /* Check whether all atoms are bonded now! */
124 for(j
=0; j
<nbonded
; j
++)
125 if (g
->nedge
[iap
[j
]-g
->start
] == 0)
128 add_gbond(g
,iap
,nbonded
);
136 void p_graph(FILE *log
,char *title
,t_graph
*g
)
140 fprintf(log
,"graph: %s\n",title
);
141 fprintf(log
,"maxedge:%d\n",g
->maxedge
);
142 fprintf(log
,"nnodes: %d\n",g
->nnodes
);
143 fprintf(log
,"nbound: %d\n",g
->nbound
);
144 fprintf(log
,"start: %d\n",g
->start
);
145 fprintf(log
,"end: %d\n",g
->end
);
146 fprintf(log
," atom shiftx shifty shiftz nedg e1 e2 etc.\n");
147 for(i
=0; (i
<g
->nnodes
); i
++)
148 if (g
->nedge
[i
] > 0) {
149 fprintf(log
,"%5d%7d%7d%7d%5d",g
->start
+i
+1,g
->ishift
[i
][XX
],g
->ishift
[i
][YY
],
150 g
->ishift
[i
][ZZ
],g
->nedge
[i
]);
151 for(j
=0; (j
<g
->nedge
[i
]); j
++)
152 fprintf(log
,"%5u",g
->edge
[i
][j
]+1);
158 static void calc_1se(t_graph
*g
,t_ilist
*il
,t_functype ftype
[],
159 short nbond
[],int natoms
)
161 int k
,nratoms
,nbonded
,tp
,end
,j
;
167 for(j
=0; (j
<end
); j
+=nratoms
+1,ia
+=nratoms
+1) {
169 nratoms
= interaction_function
[tp
].nratoms
;
171 if (tp
== F_SETTLE
) {
177 g
->start
= min(g
->start
,iaa
);
178 g
->end
= max(g
->end
,iaa
+2);
181 if (interaction_function
[tp
].flags
& IF_DUMMY
)
182 /* Bond a dummy only to the first constructing atom */
186 for(k
=0; (k
<nbonded
); k
++) {
189 g
->start
=min(g
->start
,iaa
);
190 g
->end
=max(g
->end
, iaa
);
191 if (interaction_function
[tp
].flags
& IF_GRAPH
)
199 static void calc_start_end(t_graph
*g
,t_idef
*idef
,int natoms
)
208 for(i
=0; (i
<F_NRE
); i
++) {
209 if (interaction_function
[i
].flags
& IF_GRAPH
)
210 calc_1se(g
,&idef
->il
[i
],idef
->functype
,nbond
,natoms
);
214 for(i
=g
->start
; (i
<=g
->end
); i
++)
215 nnb
=max(nnb
,nbond
[i
]);
217 fprintf(stdlog
,"Max number of graph edges per atom is %d\n",nnb
);
224 t_graph
*mk_graph(t_idef
*idef
,int natoms
,bool bShakeOnly
,bool bSettle
)
231 calc_start_end(g
,idef
,natoms
);
233 if (g
->start
>= g
->end
) {
237 g
->nnodes
=g
->end
-g
->start
+1;
238 snew(g
->ishift
,g
->nnodes
);
239 snew(g
->nedge
,g
->nnodes
);
241 /* To prevent malloc problems with many small arrays, using realloc,
242 * we allocate some more memory, and divide it ourselves.
243 * We calculate pointers... (Yuck Yuck)
246 fprintf(debug
,"MSHIFT: nnodes=%d, maxedge=%d\n",g
->nnodes
,g
->maxedge
);
247 snew(g
->edge
,g
->nnodes
);
248 snew(g
->edge
[0],g
->maxedge
*g
->nnodes
);
250 for(i
=1; (i
<g
->nnodes
); i
++)
251 g
->edge
[i
]=g
->edge
[i
-1]+g
->maxedge
;
254 /* First add all the real bonds: they should determine the molecular
257 for(i
=0; (i
<F_NRE
); i
++)
258 if (interaction_function
[i
].flags
& IF_GRAPH
)
259 mk_igraph(g
,idef
->functype
,&(idef
->il
[i
]),natoms
,TRUE
);
260 /* Then add all the other interactions in fixed lists, but first
261 * check to see what's there already.
263 for(i
=0; (i
<F_NRE
); i
++) {
264 if (!(interaction_function
[i
].flags
& IF_GRAPH
)) {
265 mk_igraph(g
,idef
->functype
,&(idef
->il
[i
]),natoms
,FALSE
);
270 /* This is a special thing used in grompp to generate shake-blocks */
271 mk_igraph(g
,idef
->functype
,&(idef
->il
[F_SHAKE
]),natoms
,TRUE
);
273 mk_igraph(g
,idef
->functype
,&(idef
->il
[F_SETTLE
]),natoms
,TRUE
);
276 for(i
=0; (i
<g
->nnodes
); i
++)
281 p_graph(stdlog
,"graph",g
);
290 void done_graph(t_graph
*g
)
295 /* This is malloced in a NASTY way, see above */
302 /************************************************************
304 * S H I F T C A L C U L A T I O N C O D E
306 ************************************************************/
308 static void mk_1shift_tric(matrix box
,rvec hbox
,rvec xi
,rvec xj
,int *mi
,int *mj
)
310 /* Calculate periodicity for triclinic box... */
316 for(m
=DIM
-1; (m
>=0); m
--) {
317 /* If dx < hbox, then xj will be reduced by box, so that
318 * xi - xj will be bigger
320 if (dx
[m
] < -hbox
[m
]) {
322 for(d
=m
-1; d
>=0; d
--)
324 } else if (dx
[m
] >= hbox
[m
]) {
326 for(d
=m
-1; d
>=0; d
--)
333 static void mk_1shift(rvec hbox
,rvec xi
,rvec xj
,int *mi
,int *mj
)
335 /* Calculate periodicity for rectangular box... */
341 for(m
=0; (m
<DIM
); m
++) {
342 /* If dx < hbox, then xj will be reduced by box, so that
343 * xi - xj will be bigger
345 if (dx
[m
] < -hbox
[m
])
347 else if (dx
[m
] >= hbox
[m
])
354 static int mk_grey(FILE *log
,int nnodes
,egCol egc
[],t_graph
*g
,int *AtomI
,
355 matrix box
,rvec x
[],int *nerror
)
362 for(m
=0; (m
<DIM
); m
++)
363 hbox
[m
]=box
[m
][m
]*0.5;
364 bTriclinic
= TRICLINIC(box
);
370 /* Loop over all the bonds */
371 for(j
=0; (j
<g
->nedge
[ai
]); j
++) {
372 aj
=g
->edge
[ai
][j
]-g0
;
373 /* If there is a white one, make it gray and set pbc */
375 mk_1shift_tric(box
,hbox
,x
[g0
+ai
],x
[g0
+aj
],g
->ishift
[ai
],is_aj
);
377 mk_1shift(hbox
,x
[g0
+ai
],x
[g0
+aj
],g
->ishift
[ai
],is_aj
);
379 if (egc
[aj
] == egcolWhite
) {
384 copy_ivec(is_aj
,g
->ishift
[aj
]);
388 else if ((is_aj
[XX
] != g
->ishift
[aj
][XX
]) ||
389 (is_aj
[YY
] != g
->ishift
[aj
][YY
]) ||
390 (is_aj
[ZZ
] != g
->ishift
[aj
][ZZ
]))
398 static int first_colour(int fC
,egCol Col
,t_graph
*g
,egCol egc
[])
399 /* Return the first node with colour Col starting at fC.
400 * return -1 if none found.
405 for(i
=fC
; (i
<g
->nnodes
); i
++)
406 if ((g
->nedge
[i
] > 0) && (egc
[i
]==Col
))
412 void mk_mshift(FILE *log
,t_graph
*g
,matrix box
,rvec x
[])
415 int nW
,nG
,nB
; /* Number of Grey, Black, White */
416 int fW
,fG
; /* First of each category */
419 /* This puts everything in the central box, that is does not move it
420 * at all. If we return without doing this for a system without bonds
421 * (i.e. only settles) all water molecules are moved to the opposite octant
423 for(i
=0; (i
<g
->nnodes
); i
++) {
424 g
->ishift
[i
][XX
]=g
->ishift
[i
][YY
]=g
->ishift
[i
][ZZ
]=0;
431 if (nnodes
> g
->negc
) {
433 srenew(g
->egc
,g
->negc
);
435 memset(g
->egc
,0,(size_t)(nnodes
*sizeof(g
->egc
[0])));
443 /* We even have a loop invariant:
444 * nW+nG+nB == g->nbound
447 fprintf(log
,"Starting W loop\n");
450 /* Find the first white, this will allways be a larger
451 * number than before, because no nodes are made white
454 if ((fW
=first_colour(fW
,egcolWhite
,g
,g
->egc
)) == -1)
455 fatal_error(0,"No WHITE nodes found while nW=%d\n",nW
);
457 /* Make the first white node grey */
458 g
->egc
[fW
]=egcolGrey
;
462 /* Initial value for the first grey */
465 fprintf(log
,"Starting G loop (nW=%d, nG=%d, nB=%d, total %d)\n",
469 if ((fG
=first_colour(fG
,egcolGrey
,g
,g
->egc
)) == -1)
470 fatal_error(0,"No GREY nodes found while nG=%d\n",nG
);
472 /* Make the first grey node black */
473 g
->egc
[fG
]=egcolBlack
;
477 /* Make all the neighbours of this black node grey
478 * and set their periodicity
480 ng
=mk_grey(log
,nnodes
,g
->egc
,g
,&fG
,box
,x
,&nerror
);
481 /* ng is the number of white nodes made grey */
487 fprintf(log
,"There were %d inconsistent shifts. Check your topology\n",
491 /************************************************************
493 * A C T U A L S H I F T C O D E
495 ************************************************************/
497 void shift_atom(t_graph
*g
,matrix box
,rvec x
[],rvec x_s
[],atom_id ai
)
500 tx
=(g
->ishift
[ai
-g
->start
])[XX
];
501 ty
=(g
->ishift
[ai
-g
->start
])[YY
];
502 tz
=(g
->ishift
[ai
-g
->start
])[ZZ
];
504 x_s
[ai
][XX
]=x
[ai
][XX
]+tx
*box
[XX
][XX
]+ty
*box
[YY
][XX
]+tz
*box
[ZZ
][XX
];
505 x_s
[ai
][YY
]=x
[ai
][YY
]+ty
*box
[YY
][YY
]+tz
*box
[ZZ
][YY
];
506 x_s
[ai
][ZZ
]=x
[ai
][ZZ
]+tz
*box
[ZZ
][ZZ
];
509 void unshift_atom(t_graph
*g
,matrix box
,rvec x
[],rvec x_s
[],atom_id ai
)
512 tx
=(g
->ishift
[ai
-g
->start
])[XX
];
513 ty
=(g
->ishift
[ai
-g
->start
])[YY
];
514 tz
=(g
->ishift
[ai
-g
->start
])[ZZ
];
516 x_s
[ai
][XX
]=x
[ai
][XX
]-tx
*box
[XX
][XX
]-ty
*box
[YY
][XX
]-tz
*box
[ZZ
][XX
];
517 x_s
[ai
][YY
]=x
[ai
][YY
]-ty
*box
[YY
][YY
]-tz
*box
[ZZ
][YY
];
518 x_s
[ai
][ZZ
]=x
[ai
][ZZ
]-tz
*box
[ZZ
][ZZ
];
521 void shift_x(t_graph
*g
,matrix box
,rvec x
[],rvec x_s
[])
532 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
537 x_s
[j
][XX
]=x
[j
][XX
]+tx
*box
[XX
][XX
]+ty
*box
[YY
][XX
]+tz
*box
[ZZ
][XX
];
538 x_s
[j
][YY
]=x
[j
][YY
]+ty
*box
[YY
][YY
]+tz
*box
[ZZ
][YY
];
539 x_s
[j
][ZZ
]=x
[j
][ZZ
]+tz
*box
[ZZ
][ZZ
];
542 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
547 x_s
[j
][XX
]=x
[j
][XX
]+tx
*box
[XX
][XX
];
548 x_s
[j
][YY
]=x
[j
][YY
]+ty
*box
[YY
][YY
];
549 x_s
[j
][ZZ
]=x
[j
][ZZ
]+tz
*box
[ZZ
][ZZ
];
555 void shift_self(t_graph
*g
,matrix box
,rvec x
[])
566 fprintf(stderr
,"Shifting atoms %d to %d\n",g0
,g0
+gn
);
569 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
574 x
[j
][XX
]=x
[j
][XX
]+tx
*box
[XX
][XX
]+ty
*box
[YY
][XX
]+tz
*box
[ZZ
][XX
];
575 x
[j
][YY
]=x
[j
][YY
]+ty
*box
[YY
][YY
]+tz
*box
[ZZ
][YY
];
576 x
[j
][ZZ
]=x
[j
][ZZ
]+tz
*box
[ZZ
][ZZ
];
579 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
584 x
[j
][XX
]=x
[j
][XX
]+tx
*box
[XX
][XX
];
585 x
[j
][YY
]=x
[j
][YY
]+ty
*box
[YY
][YY
];
586 x
[j
][ZZ
]=x
[j
][ZZ
]+tz
*box
[ZZ
][ZZ
];
592 void unshift_x(t_graph
*g
,matrix box
,rvec x
[],rvec x_s
[])
602 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
607 x
[j
][XX
]=x_s
[j
][XX
]-tx
*box
[XX
][XX
]-ty
*box
[YY
][XX
]-tz
*box
[ZZ
][XX
];
608 x
[j
][YY
]=x_s
[j
][YY
]-ty
*box
[YY
][YY
]-tz
*box
[ZZ
][YY
];
609 x
[j
][ZZ
]=x_s
[j
][ZZ
]-tz
*box
[ZZ
][ZZ
];
612 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
617 x
[j
][XX
]=x_s
[j
][XX
]-tx
*box
[XX
][XX
];
618 x
[j
][YY
]=x_s
[j
][YY
]-ty
*box
[YY
][YY
];
619 x
[j
][ZZ
]=x_s
[j
][ZZ
]-tz
*box
[ZZ
][ZZ
];
624 void unshift_self(t_graph
*g
,matrix box
,rvec x
[])
634 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
639 x
[j
][XX
]=x
[j
][XX
]-tx
*box
[XX
][XX
]-ty
*box
[YY
][XX
]-tz
*box
[ZZ
][XX
];
640 x
[j
][YY
]=x
[j
][YY
]-ty
*box
[YY
][YY
]-tz
*box
[ZZ
][YY
];
641 x
[j
][ZZ
]=x
[j
][ZZ
]-tz
*box
[ZZ
][ZZ
];
644 for(i
=0,j
=g0
; (i
<gn
); i
++,j
++) {
649 x
[j
][XX
]=x
[j
][XX
]-tx
*box
[XX
][XX
];
650 x
[j
][YY
]=x
[j
][YY
]-ty
*box
[YY
][YY
];
651 x
[j
][ZZ
]=x
[j
][ZZ
]-tz
*box
[ZZ
][ZZ
];
657 void main(int argc
,char *argv
[])
671 CopyRight(stderr
,argv
[0]);
672 parse_common_args(&argc
,argv
,&targ
,PCA_NEED_INOUT
,NULL
);
678 read_status_header(targ
.infile
,&sh
);
680 snew(mshift
,sh
.natoms
);
682 fprintf(stderr
,"Reading Status %s\n",targ
.infile
);
683 read_status(targ
.infile
,&idum
,&rdum
,&rdum
,NULL
,
684 box
,NULL
,NULL
,&idum
,x
,NULL
,NULL
,&idum
,NULL
,&top
);
686 fprintf(stderr
,"Making Graph Structure...\n");
687 g
=mk_graph(&(top
.idef
),top
.atoms
.nr
,FALSE
,FALSE
);
689 out
=ffopen(targ
.outfile
,"w");
691 fprintf(stderr
,"Making Shift...\n");
692 mk_mshift(out
,g
,box
,x
,mshift
);
694 p_graph(out
,"In Den Haag daar woont een graaf...",g
);