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 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * 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.
38 /* This file is completely threadsafe - keep it that way! */
54 #include "gmx_random.h"
55 #include "mtop_util.h"
59 typedef struct gmx_partdec_constraint
61 int left_range_receive;
62 int right_range_receive;
70 gmx_partdec_constraint_t;
73 typedef struct gmx_partdec {
74 int neighbor[2]; /* The nodeids of left and right neighb */
75 int *cgindex; /* The charge group boundaries, */
77 /* only allocated with particle decomp. */
78 int *index; /* The home particle boundaries, */
80 /* only allocated with particle decomp. */
81 int shift,bshift; /* Coordinates are shifted left for */
82 /* 'shift' systolic pulses, and right */
83 /* for 'bshift' pulses. Forces are */
84 /* shifted right for 'shift' pulses */
85 /* and left for 'bshift' pulses */
86 /* This way is not necessary to shift */
87 /* the coordinates over the entire ring */
88 rvec *vbuf; /* Buffer for summing the forces */
90 MPI_Request mpi_req_rx; /* MPI reqs for async transfers */
91 MPI_Request mpi_req_tx;
93 gmx_partdec_constraint_t * constraints;
97 void gmx_tx(const t_commrec *cr,int dir,void *buf,int bufsize)
106 nodeid = cr->pd->neighbor[dir];
109 fprintf(stderr,"gmx_tx: nodeid=%d, buf=%x, bufsize=%d\n",
113 /* workaround for crashes encountered with MPI on IRIX 6.5 */
114 if (cr->pd->mpi_req_tx != MPI_REQUEST_NULL) {
115 MPI_Test(&cr->pd->mpi_req_tx,&flag,&status);
117 fprintf(stdlog,"gmx_tx called before previous send was complete: nodeid=%d, buf=%x, bufsize=%d\n",
124 if (MPI_Isend(buf,bufsize,MPI_BYTE,RANK(cr,nodeid),tag,cr->mpi_comm_mygroup,&cr->pd->mpi_req_tx) != 0)
125 gmx_comm("MPI_Isend Failed");
129 void gmx_tx_wait(const t_commrec *cr, int dir)
132 gmx_call("gmx_tx_wait");
137 if ((mpi_result=MPI_Wait(&cr->pd->mpi_req_tx,&status)) != 0)
138 gmx_fatal(FARGS,"MPI_Wait: result=%d",mpi_result);
142 void gmx_rx(const t_commrec *cr,int dir,void *buf,int bufsize)
150 nodeid = cr->pd->neighbor[dir];
152 fprintf(stderr,"gmx_rx: nodeid=%d, buf=%x, bufsize=%d\n",
156 if (MPI_Irecv( buf, bufsize, MPI_BYTE, RANK(cr,nodeid), tag, cr->mpi_comm_mygroup, &cr->pd->mpi_req_rx) != 0 )
157 gmx_comm("MPI_Recv Failed");
161 void gmx_rx_wait(const t_commrec *cr, int nodeid)
164 gmx_call("gmx_rx_wait");
169 if ((mpi_result=MPI_Wait(&cr->pd->mpi_req_rx,&status)) != 0)
170 gmx_fatal(FARGS,"MPI_Wait: result=%d",mpi_result);
174 void gmx_tx_rx_real(const t_commrec *cr,
175 int send_dir,real *send_buf,int send_bufsize,
176 int recv_dir,real *recv_buf,int recv_bufsize)
179 gmx_call("gmx_tx_rx_real");
181 int send_nodeid,recv_nodeid;
182 int tx_tag = 0,rx_tag = 0;
185 send_nodeid = cr->pd->neighbor[send_dir];
186 recv_nodeid = cr->pd->neighbor[recv_dir];
189 #define mpi_type MPI_DOUBLE
191 #define mpi_type MPI_FLOAT
194 if (send_bufsize > 0 && recv_bufsize > 0) {
195 MPI_Sendrecv(send_buf,send_bufsize,mpi_type,RANK(cr,send_nodeid),tx_tag,
196 recv_buf,recv_bufsize,mpi_type,RANK(cr,recv_nodeid),rx_tag,
197 cr->mpi_comm_mygroup,&stat);
198 } else if (send_bufsize > 0) {
199 MPI_Send(send_buf,send_bufsize,mpi_type,RANK(cr,send_nodeid),tx_tag,
200 cr->mpi_comm_mygroup);
201 } else if (recv_bufsize > 0) {
202 MPI_Recv(recv_buf,recv_bufsize,mpi_type,RANK(cr,recv_nodeid),rx_tag,
203 cr->mpi_comm_mygroup,&stat);
210 void gmx_tx_rx_void(const t_commrec *cr,
211 int send_dir,void *send_buf,int send_bufsize,
212 int recv_dir,void *recv_buf,int recv_bufsize)
215 gmx_call("gmx_tx_rx_void");
217 int send_nodeid,recv_nodeid;
218 int tx_tag = 0,rx_tag = 0;
221 send_nodeid = cr->pd->neighbor[send_dir];
222 recv_nodeid = cr->pd->neighbor[recv_dir];
225 MPI_Sendrecv(send_buf,send_bufsize,MPI_BYTE,RANK(cr,send_nodeid),tx_tag,
226 recv_buf,recv_bufsize,MPI_BYTE,RANK(cr,recv_nodeid),rx_tag,
227 cr->mpi_comm_mygroup,&stat);
233 /*void gmx_wait(int dir_send,int dir_recv)*/
235 void gmx_wait(const t_commrec *cr, int dir_send,int dir_recv)
238 gmx_call("gmx_wait");
240 gmx_tx_wait(cr, dir_send);
241 gmx_rx_wait(cr, dir_recv);
245 static void set_left_right(t_commrec *cr)
247 cr->pd->neighbor[GMX_LEFT] = (cr->nnodes + cr->nodeid - 1) % cr->nnodes;
248 cr->pd->neighbor[GMX_RIGHT] = (cr->nodeid + 1) % cr->nnodes;
251 void pd_move_f(const t_commrec *cr,rvec f[],t_nrnb *nrnb)
253 move_f(NULL,cr,GMX_LEFT,GMX_RIGHT,f,cr->pd->vbuf,nrnb);
256 int *pd_cgindex(const t_commrec *cr)
258 return cr->pd->cgindex;
261 int *pd_index(const t_commrec *cr)
263 return cr->pd->index;
266 int pd_shift(const t_commrec *cr)
268 return cr->pd->shift;
271 int pd_bshift(const t_commrec *cr)
273 return cr->pd->bshift;
276 void pd_cg_range(const t_commrec *cr,int *cg0,int *cg1)
278 *cg0 = cr->pd->cgindex[cr->nodeid];
279 *cg1 = cr->pd->cgindex[cr->nodeid+1];
282 void pd_at_range(const t_commrec *cr,int *at0,int *at1)
284 *at0 = cr->pd->index[cr->nodeid];
285 *at1 = cr->pd->index[cr->nodeid+1];
289 pd_get_constraint_range(gmx_partdec_p_t pd,int *start,int *natoms)
291 *start = pd->constraints->left_range_receive;
292 *natoms = pd->constraints->right_range_receive-pd->constraints->left_range_receive;
296 pd_constraints_nlocalatoms(gmx_partdec_p_t pd)
300 if(NULL != pd && NULL != pd->constraints)
302 rc = pd->constraints->nlocalatoms;
314 /* This routine is used to communicate the non-home-atoms needed for constrains.
315 * We have already calculated this range of atoms during setup, and stored in the
316 * partdec constraints structure.
318 * When called, we send/receive left_range_send/receive atoms to our left (lower)
319 * node neighbor, and similar to the right (higher) node.
321 * This has not been tested for periodic molecules...
324 pd_move_x_constraints(t_commrec * cr,
330 gmx_partdec_constraint_t *pdc;
340 pdc = pd->constraints;
347 thisnode = cr->nodeid;
349 /* First pulse to right */
351 recvcnt = 3*(pd->index[thisnode]-pdc->left_range_receive);
352 sendcnt = 3*(cr->pd->index[thisnode+1]-cr->pd->constraints->right_range_send);
356 /* Assemble temporary array with both x0 & x1 */
357 recvptr = pdc->recvbuf;
358 sendptr = pdc->sendbuf;
361 for(i=pdc->right_range_send;i<pd->index[thisnode+1];i++)
363 copy_rvec(x0[i],sendptr[cnt++]);
365 for(i=pdc->right_range_send;i<pd->index[thisnode+1];i++)
367 copy_rvec(x1[i],sendptr[cnt++]);
374 recvptr = x0 + pdc->left_range_receive;
375 sendptr = x0 + pdc->right_range_send;
379 GMX_RIGHT,(real *)sendptr,sendcnt,
380 GMX_LEFT, (real *)recvptr,recvcnt);
384 /* copy back to x0/x1 */
386 for(i=pdc->left_range_receive;i<pd->index[thisnode];i++)
388 copy_rvec(recvptr[cnt++],x0[i]);
390 for(i=pdc->left_range_receive;i<pd->index[thisnode];i++)
392 copy_rvec(recvptr[cnt++],x1[i]);
396 /* And pulse to left */
397 sendcnt = 3*(pdc->left_range_send-pd->index[thisnode]);
398 recvcnt = 3*(pdc->right_range_receive-pd->index[thisnode+1]);
403 for(i=cr->pd->index[thisnode];i<pdc->left_range_send;i++)
405 copy_rvec(x0[i],sendptr[cnt++]);
407 for(i=cr->pd->index[thisnode];i<pdc->left_range_send;i++)
409 copy_rvec(x1[i],sendptr[cnt++]);
416 sendptr = x0 + pd->index[thisnode];
417 recvptr = x0 + pd->index[thisnode+1];
421 GMX_LEFT ,(real *)sendptr,sendcnt,
422 GMX_RIGHT,(real *)recvptr,recvcnt);
424 /* Final copy back from buffers */
427 /* First copy received data back into x0 & x1 */
429 for(i=pd->index[thisnode+1];i<pdc->right_range_receive;i++)
431 copy_rvec(recvptr[cnt++],x0[i]);
433 for(i=pd->index[thisnode+1];i<pdc->right_range_receive;i++)
435 copy_rvec(recvptr[cnt++],x1[i]);
441 static int home_cpu(int nnodes,gmx_partdec_t *pd,int atomid)
445 for(k=0; (k<nnodes); k++) {
446 if (atomid<pd->index[k+1])
449 gmx_fatal(FARGS,"Atomid %d is larger than number of atoms (%d)",
450 atomid+1,pd->index[nnodes]+1);
455 static void calc_nsbshift(FILE *fp,int nnodes,gmx_partdec_t *pd,t_idef *idef)
458 int lastcg,targetcg,nshift,naaj;
462 for(i=1; (i<nnodes); i++) {
463 targetcg = pd->cgindex[i];
464 for(nshift=i; (nshift > 0) && (pd->cgindex[nshift] > targetcg); nshift--)
466 pd->bshift=max(pd->bshift,i-nshift);
469 pd->shift = (nnodes + 1)/2;
470 for(i=0; (i<nnodes); i++) {
471 lastcg = pd->cgindex[i+1]-1;
472 naaj = calc_naaj(lastcg,pd->cgindex[nnodes]);
473 targetcg = (lastcg+naaj) % pd->cgindex[nnodes];
475 /* Search until we find the target charge group */
477 (nshift < nnodes) && (targetcg > pd->cgindex[nshift+1]);
480 /* Now compute the shift, that is the difference in node index */
481 nshift=((nshift - i + nnodes) % nnodes);
484 fprintf(fp,"CPU=%3d, lastcg=%5d, targetcg=%5d, myshift=%5d\n",
485 i,lastcg,targetcg,nshift);
487 /* It's the largest shift that matters */
488 pd->shift=max(nshift,pd->shift);
490 /* Now for the bonded forces */
491 for(i=0; (i<F_NRE); i++) {
492 if (interaction_function[i].flags & IF_BOND) {
493 int nratoms = interaction_function[i].nratoms;
494 for(j=0; (j<idef->il[i].nr); j+=nratoms+1) {
495 for(k=1; (k<=nratoms); k++)
496 homeid[k-1] = home_cpu(nnodes,pd,idef->il[i].iatoms[j+k]);
497 for(k=1; (k<nratoms); k++)
498 pd->shift = max(pd->shift,abs(homeid[k]-homeid[0]));
503 fprintf(fp,"pd->shift = %3d, pd->bshift=%3d\n",
504 pd->shift,pd->bshift);
509 init_partdec_constraint(t_commrec *cr,
514 gmx_partdec_t * pd = cr->pd;
515 gmx_partdec_constraint_t *pdc;
517 int ai,aj,nodei,nodej;
522 cr->pd->constraints = pdc;
528 /* Setup LINCS communication ranges */
529 pdc->left_range_receive = left_range[nodeid];
530 pdc->right_range_receive = right_range[nodeid]+1;
531 pdc->left_range_send = (nodeid > 0) ? right_range[nodeid-1]+1 : 0;
532 pdc->right_range_send = (nodeid < cr->nnodes-1) ? left_range[nodeid+1] : pd->index[cr->nnodes];
534 snew(pdc->nlocalatoms,idef->il[F_CONSTR].nr);
535 nratoms = interaction_function[F_CONSTR].nratoms;
537 for(i=0,cnt=0;i<idef->il[F_CONSTR].nr;i+=nratoms+1,cnt++)
539 ai = idef->il[F_CONSTR].iatoms[i+1];
540 aj = idef->il[F_CONSTR].iatoms[i+2];
542 while(ai>=pd->index[nodei+1])
547 while(aj>=pd->index[nodej+1])
551 pdc->nlocalatoms[cnt] = 0;
554 pdc->nlocalatoms[cnt]++;
558 pdc->nlocalatoms[cnt]++;
561 pdc->nconstraints = cnt;
563 snew(pdc->sendbuf,max(6*(pd->index[cr->nodeid+1]-pd->constraints->right_range_send),6*(pdc->left_range_send-pd->index[cr->nodeid])));
564 snew(pdc->recvbuf,max(6*(pd->index[cr->nodeid]-pdc->left_range_receive),6*(pdc->right_range_receive-pd->index[cr->nodeid+1])));
568 static void init_partdec(FILE *fp,t_commrec *cr,t_block *cgs,int *multinr,
579 if (cr->nnodes > 1) {
581 gmx_fatal(FARGS,"Internal error in init_partdec: multinr = NULL");
582 snew(pd->index,cr->nnodes+1);
583 snew(pd->cgindex,cr->nnodes+1);
586 for(i=0; (i < cr->nnodes); i++) {
587 pd->cgindex[i+1] = multinr[i];
588 pd->index[i+1] = cgs->index[multinr[i]];
590 calc_nsbshift(fp,cr->nnodes,pd,idef);
591 /* This is a hack to do with bugzilla 148 */
592 /*pd->shift = cr->nnodes-1;
595 /* Allocate a buffer of size natoms of the whole system
596 * for summing the forces over the nodes.
598 snew(pd->vbuf,cgs->index[cgs->nr]);
599 pd->constraints = NULL;
602 pd->mpi_req_tx=MPI_REQUEST_NULL;
603 pd->mpi_req_rx=MPI_REQUEST_NULL;
607 static void print_partdec(FILE *fp,const char *title,
608 int nnodes,gmx_partdec_t *pd)
612 fprintf(fp,"%s\n",title);
613 fprintf(fp,"nnodes: %5d\n",nnodes);
614 fprintf(fp,"pd->shift: %5d\n",pd->shift);
615 fprintf(fp,"pd->bshift: %5d\n",pd->bshift);
617 fprintf(fp,"Nodeid atom0 #atom cg0 #cg\n");
618 for(i=0; (i<nnodes); i++)
619 fprintf(fp,"%6d%8d%8d%8d%10d\n",
621 pd->index[i],pd->index[i+1]-pd->index[i],
622 pd->cgindex[i],pd->cgindex[i+1]-pd->cgindex[i]);
626 static void pr_idef_division(FILE *fp,t_idef *idef,int nnodes,int **multinr)
628 int i,ftype,nr,nra,m0,m1;
630 fprintf(fp,"Division of bonded forces over processors\n");
631 fprintf(fp,"%-12s","CPU");
632 for(i=0; (i<nnodes); i++)
633 fprintf(fp," %5d",i);
636 for(ftype=0; (ftype<F_NRE); ftype++) {
637 if (idef->il[ftype].nr > 0) {
638 nr = idef->il[ftype].nr;
639 nra = 1+interaction_function[ftype].nratoms;
640 fprintf(fp,"%-12s", interaction_function[ftype].name);
641 /* Loop over processors */
642 for(i=0; (i<nnodes); i++) {
643 m0 = (i == 0) ? 0 : multinr[ftype][i-1]/nra;
644 m1 = multinr[ftype][i]/nra;
645 fprintf(fp," %5d",m1-m0);
652 static void select_my_ilist(FILE *log,t_ilist *il,int *multinr,t_commrec *cr)
660 start=multinr[cr->nodeid-1];
661 end=multinr[cr->nodeid];
665 gmx_fatal(FARGS,"Negative number of atoms (%d) on node %d\n"
666 "You have probably not used the same value for -np with grompp"
671 for(i=0; (i<nr); i++)
672 ia[i]=il->iatoms[start+i];
680 static void select_my_idef(FILE *log,t_idef *idef,int **multinr,t_commrec *cr)
684 for(i=0; (i<F_NRE); i++)
685 select_my_ilist(log,&idef->il[i],multinr[i],cr);
688 gmx_localtop_t *split_system(FILE *log,
689 gmx_mtop_t *mtop,t_inputrec *inputrec,
695 int *multinr_cgs,**multinr_nre;
701 /* Time to setup the division of charge groups over processors */
702 npp = cr->nnodes-cr->npmenodes;
704 cap_env = getenv("GMX_CAPACITY");
705 if (cap_env == NULL) {
706 for(i=0; (i<npp-1); i++) {
707 capacity[i] = 1.0/(double)npp;
710 /* Take care that the sum of capacities is 1.0 */
711 capacity[npp-1] = 1.0 - tcap;
715 for(i=0; i<npp; i++) {
717 sscanf(cap_env+nn,"%lf%n",&cap,&n);
719 gmx_fatal(FARGS,"Incorrect entry or number of entries in GMX_CAPACITY='%s'",cap_env);
728 /* Convert the molecular topology to a fully listed topology */
729 top = gmx_mtop_generate_local_top(mtop,inputrec);
731 snew(multinr_cgs,npp);
732 snew(multinr_nre,F_NRE);
733 for(i=0; i<F_NRE; i++)
734 snew(multinr_nre[i],npp);
737 snew(left_range,cr->nnodes);
738 snew(right_range,cr->nnodes);
740 /* This computes which entities can be placed on processors */
741 split_top(log,npp,top,inputrec,&mtop->mols,capacity,multinr_cgs,multinr_nre,left_range,right_range);
744 init_partdec(log,cr,&(top->cgs),multinr_cgs,&(top->idef));
746 /* This should be fine */
747 /*split_idef(&(top->idef),cr->nnodes-cr->npmenodes);*/
749 select_my_idef(log,&(top->idef),multinr_nre,cr);
751 if(top->idef.il[F_CONSTR].nr>0)
753 init_partdec_constraint(cr,&(top->idef),left_range,right_range);
757 pr_idef_division(log,&(top->idef),npp,multinr_nre);
759 for(i=0; i<F_NRE; i++)
760 sfree(multinr_nre[i]);
768 print_partdec(log,"Workload division",cr->nnodes,cr->pd);
774 add_to_vsitelist(int **list, int *nitem, int *nalloc,int newitem)
781 for(i=0; i<idx && !found;i++)
783 found = (newitem ==(*list)[i]);
788 srenew(*list,*nalloc);
789 (*list)[idx++] = newitem;
794 gmx_bool setup_parallel_vsites(t_idef *idef,t_commrec *cr,
795 t_comm_vsites *vsitecomm)
804 int nalloc_left_construct,nalloc_right_construct;
805 int sendbuf[2],recvbuf[2];
806 int bufsize,leftbuf,rightbuf;
810 i0 = pd->index[cr->nodeid];
811 i1 = pd->index[cr->nodeid+1];
813 vsitecomm->left_import_construct = NULL;
814 vsitecomm->left_import_nconstruct = 0;
815 nalloc_left_construct = 0;
817 vsitecomm->right_import_construct = NULL;
818 vsitecomm->right_import_nconstruct = 0;
819 nalloc_right_construct = 0;
821 for(ftype=0; (ftype<F_NRE); ftype++)
823 if ( !(interaction_function[ftype].flags & IF_VSITE) )
828 nra = interaction_function[ftype].nratoms;
829 ia = idef->il[ftype].iatoms;
831 for(i=0; i<idef->il[ftype].nr;i+=nra+1)
835 iconstruct = ia[i+j];
838 add_to_vsitelist(&vsitecomm->left_import_construct,
839 &vsitecomm->left_import_nconstruct,
840 &nalloc_left_construct,iconstruct);
842 else if(iconstruct>=i1)
844 add_to_vsitelist(&vsitecomm->right_import_construct,
845 &vsitecomm->right_import_nconstruct,
846 &nalloc_right_construct,iconstruct);
852 /* Pre-communicate the array lengths */
854 GMX_RIGHT,(void *)&vsitecomm->right_import_nconstruct,sizeof(int),
855 GMX_LEFT, (void *)&vsitecomm->left_export_nconstruct, sizeof(int));
857 GMX_LEFT, (void *)&vsitecomm->left_import_nconstruct, sizeof(int),
858 GMX_RIGHT,(void *)&vsitecomm->right_export_nconstruct,sizeof(int));
860 snew(vsitecomm->left_export_construct, vsitecomm->left_export_nconstruct);
861 snew(vsitecomm->right_export_construct,vsitecomm->right_export_nconstruct);
863 /* Communicate the construcing atom index arrays */
865 GMX_RIGHT,(void *)vsitecomm->right_import_construct,vsitecomm->right_import_nconstruct*sizeof(int),
866 GMX_LEFT, (void *)vsitecomm->left_export_construct, vsitecomm->left_export_nconstruct*sizeof(int));
868 /* Communicate the construcing atom index arrays */
870 GMX_LEFT ,(void *)vsitecomm->left_import_construct, vsitecomm->left_import_nconstruct*sizeof(int),
871 GMX_RIGHT,(void *)vsitecomm->right_export_construct,vsitecomm->right_export_nconstruct*sizeof(int));
873 leftbuf = max(vsitecomm->left_export_nconstruct,vsitecomm->left_import_nconstruct);
874 rightbuf = max(vsitecomm->right_export_nconstruct,vsitecomm->right_import_nconstruct);
876 bufsize = max(leftbuf,rightbuf);
878 do_comm = (bufsize>0);
880 snew(vsitecomm->send_buf,2*bufsize);
881 snew(vsitecomm->recv_buf,2*bufsize);
886 t_state *partdec_init_local_state(t_commrec *cr,t_state *state_global)
889 t_state *state_local;
893 /* Copy all the contents */
894 *state_local = *state_global;
895 snew(state_local->lambda,efptNR);
896 /* local storage for lambda */
897 for (i=0;i<efptNR;i++)
899 state_local->lambda[i] = state_global->lambda[i];
901 if (state_global->nrngi > 1) {
902 /* With stochastic dynamics we need local storage for the random state */
903 if (state_local->flags & (1<<estLD_RNG)) {
904 state_local->nrng = gmx_rng_n();
905 snew(state_local->ld_rng,state_local->nrng);
908 MPI_Scatter(state_global->ld_rng,
909 state_local->nrng*sizeof(state_local->ld_rng[0]),MPI_BYTE,
910 state_local->ld_rng ,
911 state_local->nrng*sizeof(state_local->ld_rng[0]),MPI_BYTE,
912 MASTERRANK(cr),cr->mpi_comm_mygroup);
916 if (state_local->flags & (1<<estLD_RNGI)) {
917 snew(state_local->ld_rngi,1);
920 MPI_Scatter(state_global->ld_rngi,
921 sizeof(state_local->ld_rngi[0]),MPI_BYTE,
922 state_local->ld_rngi,
923 sizeof(state_local->ld_rngi[0]),MPI_BYTE,
924 MASTERRANK(cr),cr->mpi_comm_mygroup);