git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@467 f3b2605a-c512-4ea7-a41b-209d697bcdaa

This commit is contained in:
sjplimp 2007-04-10 14:32:15 +00:00
parent d556a4c51c
commit 7d192cdafa
1 changed files with 127 additions and 69 deletions

View File

@ -908,6 +908,7 @@ void Comm::reverse_comm_compute(Compute *compute)
communicate atoms to new owning procs via irregular communication
unlike exchange(), allows for atoms to move arbitrary distances
first setup irregular comm pattern, then invoke it
for triclinic, atoms must be in lamda coords (0-1) before irregular is called
------------------------------------------------------------------------- */
void Comm::irregular()
@ -929,6 +930,7 @@ void Comm::irregular()
// loop over atoms, flag any that are not in my sub-box
// fill buffer with atoms leaving my box, using < and >=
// assign which proc it belongs to
// when atom is deleted, fill it in with last atom
AtomVec *avec = atom->avec;
@ -948,7 +950,7 @@ void Comm::irregular()
if (nsend > maxsend) grow_send(nsend,1);
sizes[nsendatom] = avec->pack_exchange(i,&buf_send[nsend]);
nsend += sizes[nsendatom];
proclist[nsendatom] = 0;
proclist[nsendatom] = irregular_lookup(x[i]);
nsendatom++;
avec->copy(nlocal-1,i);
nlocal--;
@ -982,7 +984,7 @@ void Comm::irregular()
create an irregular communication plan
n = # of atoms to send
sizes = # of doubles for each atom
proclist = proc to send each atom to
proclist = proc to send each atom to (none to me)
return nrecvsize = total # of doubles I will recv
------------------------------------------------------------------------- */
@ -994,47 +996,50 @@ Comm::Plan *Comm::irregular_create(int n, int *sizes, int *proclist,
// allocate plan and work vectors
Plan *plan = (struct Plan *) memory->smalloc(sizeof(Plan),"comm:plan");
/*
int *list = new int[nprocs];
int *counts = new int[nprocs];
int *count = new int[nprocs];
// nrecv = # of messages I receive
for (i = 0; i < nprocs; i++) {
list[i] = 0;
counts[i] = 1;
count[i] = 1;
}
for (i = 0; i < n; i++) list[proclist[i]] = 1;
int nrecv;
MPI_Reduce_scatter(list,&nrecv,counts,MPI_INT,MPI_SUM,world);
MPI_Reduce_scatter(list,&nrecv,count,MPI_INT,MPI_SUM,world);
// storage for recv info
// allocate receive arrays
int *procs_from = new int[nrecv];
int *lengths_from = new int[nrecv];
int *proc_recv = new int[nrecv];
int *length_recv = new int[nrecv];
MPI_Request *request = new MPI_Request[nrecv];
MPI_Status *status = new MPI_Status[nrecv];
// nsend = # of messages I send
for (i = 0; i < nprocs; i++) list[i] = 0;
for (i = 0; i < n; i++) list[proclist[i]]++;
for (i = 0; i < n; i++) list[proclist[i]] += sizes[n];
int nsend = 0;
for (i = 0; i < nprocs; i++)
if (list[i] > 0) nsend++;
if (nself) nsend--;
if (list[i]) nsend++;
// storage for send info
// allocate send arrays
int *procs_to = new int[nsend];
int *lengths_to = new int[nsend];
int *indices_to = new int[n];
int *proc_send = new int[nsend];
int *length_send = new int[nsend];
int *num_send = new int[nsend];
int *index_send = new int[n];
int *offset_send = new int[n];
// set send info in procs_to and lengths_to
// each proc begins with iproc > me, and continues until iproc = me
// store pointer to sends in list for later use in setting indices_to
// list still stores size of message for procs I send to
// proc_send = procs I send to
// length_send = total size of message I send to each proc
// to balance pattern of send messages:
// each proc begins with iproc > me, continues until iproc = me
// reset list to store which send message each proc corresponds to
int iproc = me;
int isend = 0;
@ -1042,51 +1047,66 @@ Comm::Plan *Comm::irregular_create(int n, int *sizes, int *proclist,
iproc++;
if (iproc == nprocs) iproc = 0;
if (list[iproc] > 0) {
procs_to[isend] = iproc;
lengths_to[isend] = list[iproc];
proc_send[isend] = iproc;
length_send[isend] = list[iproc];
list[iproc] = isend;
isend++;
}
}
// tell receivers how many I'm sending
// sendmax = largest # of datums I send
// num_send = # of datums I send to each proc
int sendmax = 0;
for (i = 0; i < nsend; i++) {
MPI_Send(&lengths_to[i],1,MPI_INT,procs_to[i],0,world);
sendmax = MAX(sendmax,lengths_to[i]);
for (i = 0; i < nsend; i++) num_send[i] = 0;
for (i = 0; i < n; i++) {
isend = list[proclist[i]];
num_send[isend]++;
}
// receive sizes and sources of incoming data
// nrecvsize = total # of datums I recv
// count = offsets into n-length index_send for each proc I send to
// index_send = list of which datums to send to each proc
// 1st N1 values are datum indices for 1st proc,
// next N2 values are datum indices for 2nd proc, etc
// offset_send = where each datum starts in send buffer
*nrecvsize = 0;
for (i = 0; i < nrecv; i++) {
MPI_Recv(&lengths_from[i],1,MPI_INT,MPI_ANY_SOURCE,0,world,status);
procs_from[i] = status->MPI_SOURCE;
*nrecvsize += lengths_from[i];
}
// barrier to insure all my MPI_ANY_SOURCE messages are received
// else some procs could proceed to comm_do and start sending to me
MPI_Barrier(world);
// setup indices_to
// counts = current offset into indices_to for each proc I send to
counts[0] = 0;
for (i = 1; i < nsend; i++) counts[i] = counts[i-1] + lengths_to[i-1];
count[0] = 0;
for (i = 1; i < nsend; i++) count[i] = count[i-1] + num_send[i-1];
for (i = 0; i < n; i++) {
isend = list[proclist[i]];
indices_to[counts[isend]++] = i;
index_send[count[isend]++] = i;
if (i) offset_send[i] = offset_send[i-1] + sizes[i-1];
else offset_send[i] = 0;
}
// tell receivers how much data I send
// sendmax = largest # of datums I send in a single message
int sendmax = 0;
for (i = 0; i < nsend; i++) {
MPI_Send(&length_send[i],1,MPI_INT,proc_send[i],0,world);
sendmax = MAX(sendmax,length_send[i]);
}
// receive incoming messages
// proc_recv = procs I recv from
// length_recv = total size of message each proc sends me
// nrecvsize = total size of data I recv
*nrecvsize = 0;
for (i = 0; i < nrecv; i++) {
MPI_Recv(&length_recv[i],1,MPI_INT,MPI_ANY_SOURCE,0,world,status);
proc_recv[i] = status->MPI_SOURCE;
*nrecvsize += length_recv[i];
}
// barrier to insure all MPI_ANY_SOURCE messages are received
// else another proc could proceed to irregular_perform() and send to me
MPI_Barrier(world);
// free work vectors
delete [] counts;
delete [] count;
delete [] list;
// initialize plan and return it
@ -1095,19 +1115,22 @@ Comm::Plan *Comm::irregular_create(int n, int *sizes, int *proclist,
plan->nrecv = nrecv;
plan->sendmax = sendmax;
plan->procs_to = procs_to;
plan->lengths_to = lengths_to;
plan->indices_to = indices_to;
plan->procs_from = procs_from;
plan->lengths_from = lengths_from;
plan->proc_send = proc_send;
plan->length_send = length_send;
plan->num_send = num_send;
plan->index_send = index_send;
plan->offset_send = offset_send;
plan->proc_recv = proc_recv;
plan->length_recv = length_recv;
plan->request = request;
plan->status = status;
*/
return plan;
}
/* ----------------------------------------------------------------------
perform irregular communication
plan = previouly computed plan via irregular_create()
sendbuf = list of atoms to send
sizes = # of doubles for each atom
recvbuf = received atoms
@ -1116,15 +1139,15 @@ Comm::Plan *Comm::irregular_create(int n, int *sizes, int *proclist,
void Comm::irregular_perform(Plan *plan, double *sendbuf, int *sizes,
double *recvbuf)
{
int i,m;
int i,m,n,offset;
// post all receives
int recv_offset = 0;
offset = 0;
for (int irecv = 0; irecv < plan->nrecv; irecv++) {
MPI_Irecv(&recvbuf[recv_offset],plan->length_from[irecv],MPI_DOUBLE,
plan->proc_from[irecv],0,world,&plan->request[irecv]);
recv_offset += plan->length_from[irecv];
MPI_Irecv(&recvbuf[offset],plan->length_recv[irecv],MPI_DOUBLE,
plan->proc_recv[irecv],0,world,&plan->request[irecv]);
offset += plan->length_recv[irecv];
}
// allocate buf for largest send
@ -1136,15 +1159,14 @@ void Comm::irregular_perform(Plan *plan, double *sendbuf, int *sizes,
// pack buf with list of datums (datum = one atom)
// m = index of datum in sendbuf
int send_offset;
int ndatum = 0;
n = 0;
for (int isend = 0; isend < plan->nsend; isend++) {
send_offset = 0;
for (i = 0; i < plan->datum_send[isend]; i++) {
m = plan->index_send[ndatum++];
memcpy(&buf[send_offset],&sendbuf[plan->offset_send[m]],
offset = 0;
for (i = 0; i < plan->num_send[isend]; i++) {
m = plan->index_send[n++];
memcpy(&buf[offset],&sendbuf[plan->offset_send[m]],
sizes[m]*sizeof(double));
send_offset += sizes[m];
offset += sizes[m];
}
MPI_Send(buf,plan->length_send[isend],MPI_DOUBLE,
plan->proc_send[isend],0,world);
@ -1167,14 +1189,50 @@ void Comm::irregular_destroy(Plan *plan)
{
delete [] plan->proc_send;
delete [] plan->length_send;
delete [] plan->datum_send;
delete [] plan->num_send;
delete [] plan->index_send;
delete [] plan->offset_send;
delete [] plan->proc_from;
delete [] plan->length_from;
delete [] plan->proc_recv;
delete [] plan->length_recv;
delete [] plan->request;
delete [] plan->status;
memory->sfree(plan);
}
/* ----------------------------------------------------------------------
compute which proc owns atom with x coord
x will be in box (orthogonal) or lamda coords (triclinic)
------------------------------------------------------------------------- */
int Comm::irregular_lookup(double *x)
{
int loc[3];
if (triclinic == 0) {
double *boxlo = domain->boxlo;
double *boxhi = domain->boxhi;
loc[0] = static_cast<int>
(procgrid[0] * (x[0]-boxlo[0]) / (boxhi[0]-boxlo[0]));
loc[1] = static_cast<int>
(procgrid[1] * (x[1]-boxlo[1]) / (boxhi[1]-boxlo[1]));
loc[2] = static_cast<int>
(procgrid[2] * (x[2]-boxlo[2]) / (boxhi[2]-boxlo[2]));
} else {
loc[0] = static_cast<int> (procgrid[0] * x[0]);
loc[1] = static_cast<int> (procgrid[1] * x[1]);
loc[2] = static_cast<int> (procgrid[2] * x[2]);
}
if (loc[0] < 0) loc[0] = 0;
if (loc[0] >= procgrid[0]) loc[0] = procgrid[0] - 1;
if (loc[1] < 0) loc[1] = 0;
if (loc[1] >= procgrid[1]) loc[0] = procgrid[1] - 1;
if (loc[2] < 0) loc[2] = 0;
if (loc[2] >= procgrid[2]) loc[0] = procgrid[2] - 1;
int proc = loc[2]*procgrid[1]*procgrid[0] + loc[1]*procgrid[0] + loc[0];
return proc;
}
/* ----------------------------------------------------------------------
assign nprocs to 3d xprd,yprd,zprd box so as to minimize surface area
area = surface area of each of 3 faces of simulation box