4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
12 * Copyright (c) 1991-1999
13 * BIOSON Research Institute, Dept. of Biophysical Chemistry
14 * University of Groningen, The Netherlands
17 * GROMACS: A message-passing parallel molecular dynamics implementation
18 * H.J.C. Berendsen, D. van der Spoel and R. van Drunen
19 * Comp. Phys. Comm. 91, 43-56 (1995)
21 * Also check out our WWW page:
22 * http://md.chem.rug.nl/~gmx
27 * GRowing Old MAkes el Chrono Sweat
29 static char *SRCID_splitter_c
= "$Id$";
47 static void init_sf(int nr
,t_sf sf
[])
51 for(i
=0; (i
<nr
); i
++) {
57 static void done_sf(int nr
,t_sf sf
[])
61 for(i
=0; (i
<nr
); i
++) {
68 static void push_sf(t_sf
*sf
,int nr
,t_iatom ia
[])
72 srenew(sf
->ia
,sf
->nr
+nr
);
74 sf
->ia
[sf
->nr
+i
]=ia
[i
];
78 static int min_pid(int nr
,atom_id list
[],int hid
[])
84 for (i
=1; (i
<nr
); i
++)
85 if ((pid
=hid
[list
[i
]]) < minpid
)
91 static void split_force2(int nprocs
,int hid
[],t_idef
*idef
,t_ilist
*ilist
)
93 int i
,type
,ftype
,pid
,nratoms
,tnr
;
99 /* Walk along all the bonded forces, find the appropriate processor
100 * to calc it on, and add it to that processors list.
102 for (i
=0; i
<ilist
->nr
; i
+=(1+nratoms
)) {
103 type
= ilist
->iatoms
[i
];
104 ftype
= idef
->functype
[type
];
105 nratoms
= interaction_function
[ftype
].nratoms
;
107 if (ftype
== F_SHAKE
) {
108 /* SPECIAL CASE: All Atoms must have the same home processor! */
109 pid
=hid
[ilist
->iatoms
[i
+1]];
110 if (hid
[ilist
->iatoms
[i
+2]] != pid
)
111 fatal_error(0,"Shake block crossing processor boundaries\n"
112 "constraint between atoms (%d,%d)",
113 ilist
->iatoms
[i
+1],ilist
->iatoms
[i
+2]);
115 else if (ftype
== F_SETTLE
) {
116 /* Only the first particle is stored for settles ... */
117 ai
=ilist
->iatoms
[i
+1];
119 if ((pid
!= hid
[ai
+1]) ||
121 fatal_error(0,"Settle block crossing processor boundaries\n"
122 "constraint between atoms (%d-%d)",ai
,ai
+2);
125 pid
=min_pid(nratoms
,&ilist
->iatoms
[i
+1],hid
);
127 /* Add it to the list */
128 push_sf(&(sf
[pid
]),nratoms
+1,&(ilist
->iatoms
[i
]));
131 for(pid
=0; (pid
<MAXPROC
); pid
++) {
132 for (i
=0; (i
<sf
[pid
].nr
); i
++)
133 ilist
->iatoms
[tnr
++]=sf
[pid
].ia
[i
];
135 ilist
->multinr
[pid
]=(pid
==0) ? 0 : ilist
->multinr
[pid
-1];
136 ilist
->multinr
[pid
]+=sf
[pid
].nr
;
138 assert(tnr
==ilist
->nr
);
142 static int *home_index(int nprocs
,t_block
*cgs
)
144 /* This routine determines the processor id for each particle */
146 int pid
,j0
,j1
,j
,k
,ak
;
149 /* Initiate to -1 to make it possible to check afterwards,
150 * all hid's should be set in the loop below
152 for(k
=0; (k
<cgs
->nra
); k
++)
155 /* loop over processors */
156 for(pid
=0; (pid
<nprocs
); pid
++) {
157 j0
= (pid
==0) ? 0 : cgs
->multinr
[pid
-1];
158 j1
= cgs
->multinr
[pid
];
160 /* j0 and j1 are the boundariesin the index array */
161 for(j
=j0
; (j
<j1
); j
++) {
162 for(k
=cgs
->index
[j
]; (k
<cgs
->index
[j
+1]); k
++) {
168 /* Now verify that all hid's are not -1 */
169 for(k
=0; (k
<cgs
->nra
); k
++)
171 fatal_error(0,"hid[%d] = -1, cgs->nr = %d, cgs->nra = %d",
177 static int max_index(int start
,t_block
*b
)
184 k1
=b
->index
[start
+1];
187 for(k
=k0
+1; (k
<k1
); k
++)
194 static int min_index(int start
,t_block
*b
)
201 k1
=b
->index
[start
+1];
204 for(k
=k0
+1; (k
<k1
); k
++)
215 void set_bor(t_border
*b
,int atom
,int ic
,int is
)
222 t_border
*mk_border(bool bVerbose
,int nprocs
,t_block
*cgs
,
223 t_block
*shakes
,int *nb
)
225 int i
,ic
,is
,nbor
,ac
,as
,as0
;
228 nbor
= 1+max(cgs
->nr
,shakes
->nr
);
229 if ((shakes
->nr
> 0) && (bVerbose
)) {
231 "Going to use the WINKELHAAK Algorithm to split over %d cpus\n",
233 fprintf(stderr
,"There are %d possible border locations\n",nbor
);
239 while ((ic
< cgs
->nr
) || (is
< shakes
->nr
)) {
240 ac
= (ic
== cgs
->nr
) ? cgs
->nra
: cgs
->a
[cgs
->index
[ic
]];
241 as
= (is
== shakes
->nr
) ? shakes
->nra
: shakes
->a
[shakes
->index
[is
]];
242 as0
= (is
== 0) ? 0 : (shakes
->a
[shakes
->index
[is
]-1]);
244 fprintf(debug
,"mk_border: is=%6d ic=%6d as0=%6d as=%6d ac=%6d\n",
247 set_bor(&border
[nbor
],ac
,ic
,is
);
250 if (as
< shakes
->nra
)
253 else if ((ac
> as
) && (as
== shakes
->nra
)) {
254 set_bor(&border
[nbor
],ac
,ic
,is
);
258 else if ((ac
< as
) && (ac
> as0
)) {
259 set_bor(&border
[nbor
],ac
,ic
,is
);
268 set_bor(&border
[nbor
],cgs
->nra
,ic
,is
);
274 fprintf(debug
,"There are %d actual border entries\n",nbor
);
275 for(i
=0; (i
<nbor
); i
++)
276 fprintf(debug
,"border[%5d] = atom: %d ic: %d is: %d\n",i
,
277 border
[i
].atom
,border
[i
].ic
,border
[i
].is
);
283 static void split_blocks(bool bVerbose
,int nprocs
,
284 t_block
*cgs
,t_block
*shakes
)
286 int maxatom
[MAXPROC
];
288 int pid
,last_shk
,nbor
;
293 atom_id
*shknum
,*cgsnum
;
296 pr_block(debug
,0,"cgs",cgs
);
297 pr_block(debug
,0,"shakes",shakes
);
300 shknum
= make_invblock(shakes
,cgs
->nra
+1);
301 cgsnum
= make_invblock(cgs
,cgs
->nra
+1);
302 border
= mk_border(bVerbose
,nprocs
,cgs
,shakes
,&nbor
);
304 load
= (double)cgs
->nra
/ (double)nprocs
;
309 for(i
=0; (i
<nbor
) && (tload
< cgs
->nra
); i
++) {
317 if (fabs(b0
-tload
)<fabs(b1
-tload
)) {
319 cgs
->multinr
[pid
] = border
[i
].ic
;
320 shakes
->multinr
[pid
] = border
[i
].is
;
326 /* Now the last one... */
327 while (pid
< nprocs
) {
328 cgs
->multinr
[pid
]=cgs
->nr
;
329 shakes
->multinr
[pid
]=shakes
->nr
;
330 maxatom
[pid
]=cgs
->nra
;
334 fatal_error(0,"pid = %d, nprocs = %d, file %s, line %d",
335 pid
,nprocs
,__FILE__
,__LINE__
);
339 for(i
=nprocs
-1; (i
>0); i
--)
340 maxatom
[i
]-=maxatom
[i
-1];
341 fprintf(stderr
,"Division over processors in atoms:\n");
342 for(i
=0; (i
<nprocs
); i
++)
343 fprintf(stderr
,"%6d",maxatom
[i
]);
344 fprintf(stderr
,"\n");
351 static void def_mnr(int nr
,int mnr
[])
355 for (i
=0; (i
<MAXPROC
); i
++)
360 void split_top(bool bVerbose
,int nprocs
,t_topology
*top
)
365 if ((bVerbose
) && (nprocs
>1))
366 fprintf(stderr
,"splitting topology...\n");
368 for(j
=0; (j
<F_NRE
); j
++)
369 def_mnr(top
->idef
.il
[j
].nr
,top
->idef
.il
[j
].multinr
);
370 def_mnr(top
->atoms
.excl
.nr
,top
->atoms
.excl
.multinr
);
372 for (j
=0; j
<ebNR
; j
++)
373 def_mnr(top
->blocks
[j
].nr
,top
->blocks
[j
].multinr
);
376 split_blocks(bVerbose
,nprocs
,
377 &(top
->blocks
[ebCGS
]),&(top
->blocks
[ebSBLOCKS
]));
378 homeind
=home_index(nprocs
,&(top
->blocks
[ebCGS
]));
379 for(j
=0; (j
<F_NRE
); j
++)
380 split_force2(nprocs
,homeind
,&top
->idef
,&top
->idef
.il
[j
]);
389 static int sid_comp(const void *a
,const void *b
)
399 return (sa
->atom
-sb
->atom
);
404 typedef enum { egcolWhite
, egcolGrey
, egcolBlack
, egcolNR
} egCol
;
406 static int mk_grey(int nnodes
,egCol egc
[],t_graph
*g
,int *AtomI
,
415 /* Loop over all the bonds */
416 for(j
=0; (j
<g
->nedge
[ai
]); j
++) {
417 aj
=g
->edge
[ai
][j
]-g0
;
418 /* If there is a white one, make it gray and set pbc */
419 if (egc
[aj
] == egcolWhite
) {
424 /* Check whether this one has been set before... */
425 if (sid
[aj
+g0
].sid
!= -1)
426 fatal_error(0,"sid[%d]=%d, sid[%d]=%d, file %s, line %d",
427 ai
,sid
[ai
+g0
].sid
,aj
,sid
[aj
+g0
].sid
,__FILE__
,__LINE__
);
429 sid
[aj
+g0
].sid
= sid
[ai
+g0
].sid
;
430 sid
[aj
+g0
].atom
= aj
+g0
;
438 static int first_colour(int fC
,egCol Col
,t_graph
*g
,egCol egc
[])
439 /* Return the first node with colour Col starting at fC.
440 * return -1 if none found.
445 for(i
=fC
; (i
<g
->nnodes
); i
++)
446 if ((g
->nedge
[i
] > 0) && (egc
[i
]==Col
))
452 static int mk_sblocks(bool bVerbose
,t_graph
*g
,t_sid sid
[])
455 int nW
,nG
,nB
; /* Number of Grey, Black, White */
456 int fW
,fG
; /* First of each category */
457 static egCol
*egc
=NULL
; /* The colour of each node */
475 /* We even have a loop invariant:
476 * nW+nG+nB == g->nbound
480 fprintf(stderr
,"Walking down the molecule graph to make shake-blocks\n");
483 /* Find the first white, this will allways be a larger
484 * number than before, because no nodes are made white
487 if ((fW
=first_colour(fW
,egcolWhite
,g
,egc
)) == -1)
488 fatal_error(0,"No WHITE nodes found while nW=%d\n",nW
);
490 /* Make the first white node grey, and set the block number */
492 sid
[fW
+g0
].sid
= nblock
++;
496 /* Initial value for the first grey */
500 fprintf(debug
,"Starting G loop (nW=%d, nG=%d, nB=%d, total %d)\n",
504 if ((fG
=first_colour(fG
,egcolGrey
,g
,egc
)) == -1)
505 fatal_error(0,"No GREY nodes found while nG=%d\n",nG
);
507 /* Make the first grey node black */
512 /* Make all the neighbours of this black node grey
513 * and set their block number
515 ng
=mk_grey(nnodes
,egc
,g
,&fG
,sid
);
516 /* ng is the number of white nodes made grey */
526 void gen_sblocks(bool bVerbose
,int natoms
,t_idef
*idef
,t_block
*sblock
)
533 g
=mk_graph(idef
,natoms
,TRUE
);
534 if (bVerbose
&& debug
)
535 p_graph(debug
,"Graaf Dracula",g
);
537 for(i
=0; (i
<natoms
); i
++) {
541 nsid
=mk_sblocks(bVerbose
,g
,sid
);
543 /* Now sort the shake blocks... */
544 qsort(sid
,natoms
,(size_t)sizeof(sid
[0]),sid_comp
);
546 /* Now check how many are NOT -1, i.e. how many have to be shaken */
547 for(i
=0; (i
<natoms
); i
++)
551 /* Fill the sblock struct */
553 sblock
->nra
= natoms
-i
;
554 srenew(sblock
->a
,sblock
->nra
);
555 srenew(sblock
->index
,sblock
->nr
+1);
562 for(j
=0 ; (i
<natoms
); i
++,j
++) {
563 sblock
->a
[j
]=sid
[i
].atom
;
564 if (sid
[i
].sid
!= isid
) {
573 fatal_error(0,"k=%d, nsid=%d\n",k
,nsid
);