added rendezvous alg to fix shake

This commit is contained in:
Steve Plimpton 2018-12-12 17:14:56 -07:00 committed by Axel Kohlmeyer
parent a3a16acead
commit b370a61b60
No known key found for this signature in database
GPG Key ID: D9B44E93BF0C375A
5 changed files with 899 additions and 585 deletions

View File

@ -414,9 +414,9 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) :
if (comm->me == 0) {
if (screen)
fprintf(screen," create_bodies CPU = %g secs\n",time2-time1);
fprintf(screen," create bodies CPU = %g secs\n",time2-time1);
if (logfile)
fprintf(logfile," create_bodies CPU = %g secs\n",time2-time1);
fprintf(logfile," create bodies CPU = %g secs\n",time2-time1);
}
// set nlocal_body and allocate bodies I own
@ -1749,6 +1749,8 @@ int FixRigidSmall::rendezvous_body(int n, char *inbuf,
memory->destroy(iclose);
memory->destroy(rsqclose);
// flag = 2: new outbuf
rflag = 2;
return nout;
}

View File

@ -219,8 +219,19 @@ FixShake::FixShake(LAMMPS *lmp, int narg, char **arg) :
// identify all SHAKE clusters
double time1 = MPI_Wtime();
find_clusters();
double time2 = MPI_Wtime();
if (comm->me == 0) {
if (screen)
fprintf(screen," find clusters CPU = %g secs\n",time2-time1);
if (logfile)
fprintf(logfile," find clusters CPU = %g secs\n",time2-time1);
}
// initialize list of SHAKE clusters to constrain
maxlist = 0;
@ -707,13 +718,6 @@ void FixShake::find_clusters()
int nlocal = atom->nlocal;
int angles_allow = atom->avec->angles_allow;
// setup ring of procs
int next = me + 1;
int prev = me -1;
if (next == nprocs) next = 0;
if (prev < 0) prev = nprocs - 1;
// -----------------------------------------------------
// allocate arrays for self (1d) and bond partners (2d)
// max = max # of bond partners for owned atoms = 2nd dim of partner arrays
@ -755,6 +759,10 @@ void FixShake::find_clusters()
memory->create(partner_shake,nlocal,max,"shake:partner_shake");
memory->create(partner_nshake,nlocal,max,"shake:partner_nshake");
// setup atomIDs and procowner vectors in rendezvous decomposition
atom_owners();
// -----------------------------------------------------
// set npartner and partner_tag from special arrays
// -----------------------------------------------------
@ -778,86 +786,13 @@ void FixShake::find_clusters()
}
// -----------------------------------------------------
// set partner_mask, partner_type, partner_massflag, partner_bondtype
// for bonded partners
// requires communication for off-proc partners
// set partner_mask, partner_type, partner_massflag,
// partner_bondtype for all my bonded partners
// requires rendezvous communication for off-proc partners
// -----------------------------------------------------
// fill in mask, type, massflag, bondtype if own bond partner
// info to store in buf for each off-proc bond = nper = 6
// 2 atoms IDs in bond, space for mask, type, massflag, bondtype
// nbufmax = largest buffer needed to hold info from any proc
int nper = 6;
nbuf = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
partner_mask[i][j] = 0;
partner_type[i][j] = 0;
partner_massflag[i][j] = 0;
partner_bondtype[i][j] = 0;
m = atom->map(partner_tag[i][j]);
if (m >= 0 && m < nlocal) {
partner_mask[i][j] = mask[m];
partner_type[i][j] = type[m];
if (nmass) {
if (rmass) massone = rmass[m];
else massone = mass[type[m]];
partner_massflag[i][j] = masscheck(massone);
}
n = bondtype_findset(i,tag[i],partner_tag[i][j],0);
if (n) partner_bondtype[i][j] = n;
else {
n = bondtype_findset(m,tag[i],partner_tag[i][j],0);
if (n) partner_bondtype[i][j] = n;
}
} else nbuf += nper;
}
}
memory->create(buf,nbuf,"shake:buf");
// fill buffer with info
size = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
m = atom->map(partner_tag[i][j]);
if (m < 0 || m >= nlocal) {
buf[size] = tag[i];
buf[size+1] = partner_tag[i][j];
buf[size+2] = 0;
buf[size+3] = 0;
buf[size+4] = 0;
n = bondtype_findset(i,tag[i],partner_tag[i][j],0);
if (n) buf[size+5] = n;
else buf[size+5] = 0;
size += nper;
}
}
}
// cycle buffer around ring of procs back to self
comm->ring(size,sizeof(tagint),buf,1,ring_bonds,buf,(void *)this);
// store partner info returned to me
m = 0;
while (m < size) {
i = atom->map(buf[m]);
for (j = 0; j < npartner[i]; j++)
if (buf[m+1] == partner_tag[i][j]) break;
partner_mask[i][j] = buf[m+2];
partner_type[i][j] = buf[m+3];
partner_massflag[i][j] = buf[m+4];
partner_bondtype[i][j] = buf[m+5];
m += nper;
}
memory->destroy(buf);
partner_info(npartner,partner_tag,partner_mask,partner_type,
partner_massflag,partner_bondtype);
// error check for unfilled partner info
// if partner_type not set, is an error
@ -868,17 +803,18 @@ void FixShake::find_clusters()
// else it's an error
flag = 0;
int flag2 = 0;
for (i = 0; i < nlocal; i++)
for (j = 0; j < npartner[i]; j++) {
if (partner_type[i][j] == 0) flag = 1;
if (partner_type[i][j] == 0) flag++;
if (!(mask[i] & groupbit)) continue;
if (!(partner_mask[i][j] & groupbit)) continue;
if (partner_bondtype[i][j] == 0) flag = 1;
if (partner_bondtype[i][j] == 0) flag2++;
}
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Did not find fix shake partner info");
// -----------------------------------------------------
// identify SHAKEable bonds
// set nshake[i] = # of SHAKE bonds attached to atom i
@ -931,56 +867,11 @@ void FixShake::find_clusters()
// -----------------------------------------------------
// set partner_nshake for bonded partners
// requires communication for off-proc partners
// requires rendezvous communication for off-proc partners
// -----------------------------------------------------
// fill in partner_nshake if own bond partner
// info to store in buf for each off-proc bond =
// 2 atoms IDs in bond, space for nshake value
// nbufmax = largest buffer needed to hold info from any proc
nbuf = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
m = atom->map(partner_tag[i][j]);
if (m >= 0 && m < nlocal) partner_nshake[i][j] = nshake[m];
else nbuf += 3;
}
}
memory->create(buf,nbuf,"shake:buf");
// fill buffer with info
size = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
m = atom->map(partner_tag[i][j]);
if (m < 0 || m >= nlocal) {
buf[size] = tag[i];
buf[size+1] = partner_tag[i][j];
size += 3;
}
}
}
// cycle buffer around ring of procs back to self
comm->ring(size,sizeof(tagint),buf,2,ring_nshake,buf,(void *)this);
// store partner info returned to me
m = 0;
while (m < size) {
i = atom->map(buf[m]);
for (j = 0; j < npartner[i]; j++)
if (buf[m+1] == partner_tag[i][j]) break;
partner_nshake[i][j] = buf[m+2];
m += 3;
}
memory->destroy(buf);
nshake_info(npartner,partner_tag,partner_nshake);
// -----------------------------------------------------
// error checks
// no atom with nshake > 3
@ -988,7 +879,7 @@ void FixShake::find_clusters()
// -----------------------------------------------------
flag = 0;
for (i = 0; i < nlocal; i++) if (nshake[i] > 3) flag = 1;
for (i = 0; i < nlocal; i++) if (nshake[i] > 3) flag++;
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Shake cluster of more than 4 atoms");
@ -996,7 +887,7 @@ void FixShake::find_clusters()
for (i = 0; i < nlocal; i++) {
if (nshake[i] <= 1) continue;
for (j = 0; j < npartner[i]; j++)
if (partner_shake[i][j] && partner_nshake[i][j] > 1) flag = 1;
if (partner_shake[i][j] && partner_nshake[i][j] > 1) flag++;
}
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Shake clusters are connected");
@ -1067,60 +958,7 @@ void FixShake::find_clusters()
// requires communication for off-proc atoms
// -----------------------------------------------------
// fill in shake arrays for each bond partner I own
// info to store in buf for each off-proc bond =
// all values from shake_flag, shake_atom, shake_type
// nbufmax = largest buffer needed to hold info from any proc
nbuf = 0;
for (i = 0; i < nlocal; i++) {
if (shake_flag[i] == 0) continue;
for (j = 0; j < npartner[i]; j++) {
if (partner_shake[i][j] == 0) continue;
m = atom->map(partner_tag[i][j]);
if (m >= 0 && m < nlocal) {
shake_flag[m] = shake_flag[i];
shake_atom[m][0] = shake_atom[i][0];
shake_atom[m][1] = shake_atom[i][1];
shake_atom[m][2] = shake_atom[i][2];
shake_atom[m][3] = shake_atom[i][3];
shake_type[m][0] = shake_type[i][0];
shake_type[m][1] = shake_type[i][1];
shake_type[m][2] = shake_type[i][2];
} else nbuf += 9;
}
}
memory->create(buf,nbuf,"shake:buf");
// fill buffer with info
size = 0;
for (i = 0; i < nlocal; i++) {
if (shake_flag[i] == 0) continue;
for (j = 0; j < npartner[i]; j++) {
if (partner_shake[i][j] == 0) continue;
m = atom->map(partner_tag[i][j]);
if (m < 0 || m >= nlocal) {
buf[size] = partner_tag[i][j];
buf[size+1] = shake_flag[i];
buf[size+2] = shake_atom[i][0];
buf[size+3] = shake_atom[i][1];
buf[size+4] = shake_atom[i][2];
buf[size+5] = shake_atom[i][3];
buf[size+6] = shake_type[i][0];
buf[size+7] = shake_type[i][1];
buf[size+8] = shake_type[i][2];
size += 9;
}
}
}
// cycle buffer around ring of procs back to self
comm->ring(size,sizeof(tagint),buf,3,ring_shake,NULL,(void *)this);
memory->destroy(buf);
shake_info(npartner,partner_tag,partner_shake);
// -----------------------------------------------------
// free local memory
@ -1199,98 +1037,549 @@ void FixShake::find_clusters()
}
/* ----------------------------------------------------------------------
when receive buffer, scan bond partner IDs for atoms I own
if I own partner:
fill in mask and type and massflag
search for bond with 1st atom and fill in bondtype
setup atomIDs and procowner
------------------------------------------------------------------------- */
void FixShake::ring_bonds(int ndatum, char *cbuf, void *ptr)
void FixShake::atom_owners()
{
FixShake *fsptr = (FixShake *)ptr;
Atom *atom = fsptr->atom;
tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int *proclist;
memory->create(proclist,nlocal,"shake:proclist");
IDRvous *idbuf = (IDRvous *)
memory->smalloc((bigint) nlocal*sizeof(IDRvous),"shake:idbuf");
// setup input buf to rendezvous comm
// input datums = pairs of bonded atoms
// owning proc for each datum = random hash of atomID
// one datum for each owned atom: datum = owning proc, atomID
for (int i = 0; i < nlocal; i++) {
proclist[i] = tag[i] % nprocs;
idbuf[i].me = me;
idbuf[i].atomID = tag[i];
}
// perform rendezvous operation
// each proc assigned every 1/Pth atom
char *buf;
comm->rendezvous(nlocal,proclist,
(char *) idbuf,sizeof(IDRvous),
rendezvous_ids,buf,0,(void *) this);
memory->destroy(proclist);
memory->sfree(idbuf);
}
/* ----------------------------------------------------------------------
setup partner_mask, partner_type, partner_massflag, partner_bondtype
------------------------------------------------------------------------- */
void FixShake::partner_info(int *npartner, tagint **partner_tag,
int **partner_mask, int **partner_type,
int **partner_massflag, int **partner_bondtype)
{
int i,j,m,n;
int nlocal = atom->nlocal;
// nsend = # of my datums to send
// one datum for every off-processor partner
int nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
m = atom->map(partner_tag[i][j]);
if (m < 0 || m >= nlocal) nsend++;
}
}
int *proclist;
memory->create(proclist,nsend,"special:proclist");
PartnerInfo *inbuf = (PartnerInfo *)
memory->smalloc((bigint) nsend*sizeof(PartnerInfo),"special:inbuf");
// set values in 4 partner arrays for all partner atoms I own
// also setup input buf to rendezvous comm
// input datums = pair of bonded atoms where I do not own partner
// owning proc for each datum = partner_tag % nprocs
// datum: atomID = partner_tag (off-proc), partnerID = tag (on-proc)
// 4 values for my owned atom
double *rmass = atom->rmass;
double *mass = atom->mass;
int *mask = atom->mask;
int *type = atom->type;
int *mask = atom->mask;
tagint *tag = atom->tag;
double massone;
nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
partner_mask[i][j] = 0;
partner_type[i][j] = 0;
partner_massflag[i][j] = 0;
partner_bondtype[i][j] = 0;
m = atom->map(partner_tag[i][j]);
if (m >= 0 && m < nlocal) {
partner_mask[i][j] = mask[m];
partner_type[i][j] = type[m];
if (nmass) {
if (rmass) massone = rmass[m];
else massone = mass[type[m]];
partner_massflag[i][j] = masscheck(massone);
}
n = bondtype_findset(i,tag[i],partner_tag[i][j],0);
if (n) partner_bondtype[i][j] = n;
else {
n = bondtype_findset(m,tag[i],partner_tag[i][j],0);
if (n) partner_bondtype[i][j] = n;
}
} else {
proclist[nsend] = partner_tag[i][j] % nprocs;
inbuf[nsend].atomID = partner_tag[i][j];
inbuf[nsend].partnerID = tag[i];
inbuf[nsend].mask = mask[i];
inbuf[nsend].type = type[i];
if (nmass) {
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
inbuf[nsend].massflag = masscheck(massone);
} else inbuf[nsend].massflag = 0;
// my atom may own bond, in which case set partner_bondtype
// else receiver of this datum will own the bond and return the value
n = bondtype_findset(i,tag[i],partner_tag[i][j],0);
if (n) {
partner_bondtype[i][j] = n;
inbuf[nsend].bondtype = n;
} else inbuf[nsend].bondtype = 0;
nsend++;
}
}
}
// perform rendezvous operation
// each proc owns random subset of atoms
// receives all data needed to populate un-owned partner 4 values
char *buf;
int nreturn = comm->rendezvous(nsend,proclist,
(char *) inbuf,sizeof(PartnerInfo),
rendezvous_partners_info,buf,sizeof(PartnerInfo),
(void *) this);
PartnerInfo *outbuf = (PartnerInfo *) buf;
memory->destroy(proclist);
memory->sfree(inbuf);
// set partner 4 values for un-onwed partners based on output info
// outbuf.atomID = my owned atom, outbuf.partnerID = partner the info is for
for (m = 0; m < nreturn; m++) {
i = atom->map(outbuf[m].atomID);
for (j = 0; j < npartner[i]; j++)
if (partner_tag[i][j] == outbuf[m].partnerID) break;
partner_mask[i][j] = outbuf[m].mask;
partner_type[i][j] = outbuf[m].type;
partner_massflag[i][j] = outbuf[m].massflag;
// only set partner_bondtype if my atom did not set it when setting up rendezvous
// if this proc set it, then sender of this datum set outbuf.bondtype = 0
if (partner_bondtype[i][j] == 0)
partner_bondtype[i][j] = outbuf[m].bondtype;
}
memory->sfree(outbuf);
}
/* ----------------------------------------------------------------------
setup partner_nshake
------------------------------------------------------------------------- */
void FixShake::nshake_info(int *npartner, tagint **partner_tag,
int **partner_nshake)
{
int i,j,m,n;
int nlocal = atom->nlocal;
// nsend = # of my datums to send
// one datum for every off-processor partner
int nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
m = atom->map(partner_tag[i][j]);
if (m < 0 || m >= nlocal) nsend++;
}
}
int *proclist;
memory->create(proclist,nsend,"special:proclist");
NShakeInfo *inbuf = (NShakeInfo *)
memory->smalloc((bigint) nsend*sizeof(NShakeInfo),"special:inbuf");
// set partner_nshake for all partner atoms I own
// also setup input buf to rendezvous comm
// input datums = pair of bonded atoms where I do not own partner
// owning proc for each datum = partner_tag % nprocs
// datum: atomID = partner_tag (off-proc), partnerID = tag (on-proc)
// nshake value for my owned atom
tagint *tag = atom->tag;
nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
partner_nshake[i][j] = 0;
m = atom->map(partner_tag[i][j]);
if (m >= 0 && m < nlocal) {
partner_nshake[i][j] = nshake[m];
} else {
proclist[nsend] = partner_tag[i][j] % nprocs;
inbuf[nsend].atomID = partner_tag[i][j];
inbuf[nsend].partnerID = tag[i];
inbuf[nsend].nshake = nshake[i];
nsend++;
}
}
}
// perform rendezvous operation
// each proc owns random subset of atoms
// receives all data needed to populate un-owned partner nshake
char *buf;
int nreturn = comm->rendezvous(nsend,proclist,
(char *) inbuf,sizeof(NShakeInfo),
rendezvous_nshake,buf,sizeof(NShakeInfo),
(void *) this);
NShakeInfo *outbuf = (NShakeInfo *) buf;
memory->destroy(proclist);
memory->sfree(inbuf);
// set partner nshake for un-onwed partners based on output info
// outbuf.atomID = my owned atom, outbuf.partnerID = partner the info is for
for (m = 0; m < nreturn; m++) {
i = atom->map(outbuf[m].atomID);
for (j = 0; j < npartner[i]; j++)
if (partner_tag[i][j] == outbuf[m].partnerID) break;
partner_nshake[i][j] = outbuf[m].nshake;
}
memory->sfree(outbuf);
}
/* ----------------------------------------------------------------------
setup shake_flag, shake_atom, shake_type
------------------------------------------------------------------------- */
void FixShake::shake_info(int *npartner, tagint **partner_tag,
int **partner_shake)
{
int i,j,m,n;
int nlocal = atom->nlocal;
// nsend = # of my datums to send
// one datum for every off-processor partner
int nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
m = atom->map(partner_tag[i][j]);
if (m < 0 || m >= nlocal) nsend++;
}
}
int *proclist;
memory->create(proclist,nsend,"special:proclist");
ShakeInfo *inbuf = (ShakeInfo *)
memory->smalloc((bigint) nsend*sizeof(ShakeInfo),"special:inbuf");
// set 3 shake arrays for all partner atoms I own
// also setup input buf to rendezvous comm
// input datums = partner atom where I do not own partner
// owning proc for each datum = partner_tag % nprocs
// datum: atomID = partner_tag (off-proc)
// values in 3 shake arrays
nsend = 0;
for (i = 0; i < nlocal; i++) {
if (shake_flag[i] == 0) continue;
for (j = 0; j < npartner[i]; j++) {
if (partner_shake[i][j] == 0) continue;
m = atom->map(partner_tag[i][j]);
if (m >= 0 && m < nlocal) {
shake_flag[m] = shake_flag[i];
shake_atom[m][0] = shake_atom[i][0];
shake_atom[m][1] = shake_atom[i][1];
shake_atom[m][2] = shake_atom[i][2];
shake_atom[m][3] = shake_atom[i][3];
shake_type[m][0] = shake_type[i][0];
shake_type[m][1] = shake_type[i][1];
shake_type[m][2] = shake_type[i][2];
} else {
proclist[nsend] = partner_tag[i][j] % nprocs;
inbuf[nsend].atomID = partner_tag[i][j];
inbuf[nsend].shake_flag = shake_flag[i];
inbuf[nsend].shake_atom[0] = shake_atom[i][0];
inbuf[nsend].shake_atom[1] = shake_atom[i][1];
inbuf[nsend].shake_atom[2] = shake_atom[i][2];
inbuf[nsend].shake_atom[3] = shake_atom[i][3];
inbuf[nsend].shake_type[0] = shake_type[i][0];
inbuf[nsend].shake_type[1] = shake_type[i][1];
inbuf[nsend].shake_type[2] = shake_type[i][2];
nsend++;
}
}
}
// perform rendezvous operation
// each proc owns random subset of atoms
// receives all data needed to populate un-owned shake info
char *buf;
int nreturn = comm->rendezvous(nsend,proclist,
(char *) inbuf,sizeof(ShakeInfo),
rendezvous_shake,buf,sizeof(ShakeInfo),
(void *) this);
ShakeInfo *outbuf = (ShakeInfo *) buf;
memory->destroy(proclist);
memory->sfree(inbuf);
// set shake info for un-onwed partners based on output info
for (m = 0; m < nreturn; m++) {
i = atom->map(outbuf[m].atomID);
shake_flag[i] = outbuf[m].shake_flag;
shake_atom[i][0] = outbuf[m].shake_atom[0];
shake_atom[i][1] = outbuf[m].shake_atom[1];
shake_atom[i][2] = outbuf[m].shake_atom[2];
shake_atom[i][3] = outbuf[m].shake_atom[3];
shake_type[i][0] = outbuf[m].shake_type[0];
shake_type[i][1] = outbuf[m].shake_type[1];
shake_type[i][2] = outbuf[m].shake_type[2];
}
memory->sfree(outbuf);
}
/* ----------------------------------------------------------------------
process data for atoms assigned to me in rendezvous decomposition
inbuf = list of N IDRvous datums
no outbuf
------------------------------------------------------------------------- */
int FixShake::rendezvous_ids(int n, char *inbuf,
int &flag, int *&proclist, char *&outbuf,
void *ptr)
{
FixShake *fsptr = (FixShake *) ptr;
Memory *memory = fsptr->memory;
int *procowner;
tagint *atomIDs;
memory->create(procowner,n,"special:procowner");
memory->create(atomIDs,n,"special:atomIDs");
IDRvous *in = (IDRvous *) inbuf;
for (int i = 0; i < n; i++) {
procowner[i] = in[i].me;
atomIDs[i] = in[i].atomID;
}
// store rendezvous data in FixShake class
fsptr->nrvous = n;
fsptr->procowner = procowner;
fsptr->atomIDs = atomIDs;
// flag = 0: no 2nd irregular comm needed in comm->rendezvous
flag = 0;
return 0;
}
/* ----------------------------------------------------------------------
process data for atoms assigned to me in rendezvous decomposition
inbuf = list of N PairRvous datums
outbuf = same list of N PairRvous datums, routed to different procs
------------------------------------------------------------------------- */
int FixShake::rendezvous_partners_info(int n, char *inbuf,
int &flag, int *&proclist, char *&outbuf,
void *ptr)
{
int i,m;
FixShake *fsptr = (FixShake *) ptr;
Atom *atom = fsptr->atom;
Memory *memory = fsptr->memory;
// clear atom map so it can be here as a hash table
// faster than an STL map for large atom counts
atom->map_clear();
// hash atom IDs stored in rendezvous decomposition
int nrvous = fsptr->nrvous;
tagint *atomIDs = fsptr->atomIDs;
for (i = 0; i < nrvous; i++)
atom->map_one(atomIDs[i],i);
// proclist = owner of atomID in caller decomposition
// outbuf = info about owned atomID = 4 values
PartnerInfo *in = (PartnerInfo *) inbuf;
int *procowner = fsptr->procowner;
memory->create(proclist,n,"shake:proclist");
double massone;
int nmass = fsptr->nmass;
tagint *buf = (tagint *) cbuf;
int m,n;
double massone;
for (int i = 0; i < ndatum; i += 6) {
m = atom->map(buf[i+1]);
if (m >= 0 && m < nlocal) {
buf[i+2] = mask[m];
buf[i+3] = type[m];
if (nmass) {
if (rmass) massone = rmass[m];
else massone = mass[type[m]];
buf[i+4] = fsptr->masscheck(massone);
}
if (buf[i+5] == 0) {
n = fsptr->bondtype_findset(m,buf[i],buf[i+1],0);
if (n) buf[i+5] = n;
}
}
for (i = 0; i < n; i++) {
m = atom->map(in[i].atomID);
proclist[i] = procowner[m];
}
outbuf = inbuf;
// re-create atom map
atom->map_init(0);
atom->nghost = 0;
atom->map_set();
// flag = 1: outbuf = inbuf
flag = 1;
return n;
}
/* ----------------------------------------------------------------------
when receive buffer, scan bond partner IDs for atoms I own
if I own partner, fill in nshake value
process data for atoms assigned to me in rendezvous decomposition
inbuf = list of N NShakeInfo datums
outbuf = same list of N NShakeInfo datums, routed to different procs
------------------------------------------------------------------------- */
void FixShake::ring_nshake(int ndatum, char *cbuf, void *ptr)
int FixShake::rendezvous_nshake(int n, char *inbuf,
int &flag, int *&proclist, char *&outbuf,
void *ptr)
{
FixShake *fsptr = (FixShake *)ptr;
int i,j,m;
FixShake *fsptr = (FixShake *) ptr;
Atom *atom = fsptr->atom;
int nlocal = atom->nlocal;
Memory *memory = fsptr->memory;
int *nshake = fsptr->nshake;
// clear atom map so it can be here as a hash table
// faster than an STL map for large atom counts
tagint *buf = (tagint *) cbuf;
int m;
atom->map_clear();
for (int i = 0; i < ndatum; i += 3) {
m = atom->map(buf[i+1]);
if (m >= 0 && m < nlocal) buf[i+2] = nshake[m];
// hash atom IDs stored in rendezvous decomposition
int nrvous = fsptr->nrvous;
tagint *atomIDs = fsptr->atomIDs;
for (i = 0; i < nrvous; i++)
atom->map_one(atomIDs[i],i);
// proclist = owner of atomID in caller decomposition
// outbuf = info about owned atomID
NShakeInfo *in = (NShakeInfo *) inbuf;
int *procowner = fsptr->procowner;
memory->create(proclist,n,"shake:proclist");
for (i = 0; i < n; i++) {
m = atom->map(in[i].atomID);
proclist[i] = procowner[m];
}
outbuf = inbuf;
// re-create atom map
atom->map_init(0);
atom->nghost = 0;
atom->map_set();
// flag = 1: outbuf = inbuf
flag = 1;
return n;
}
/* ----------------------------------------------------------------------
when receive buffer, scan bond partner IDs for atoms I own
if I own partner, fill in nshake value
process data for atoms assigned to me in rendezvous decomposition
inbuf = list of N PairRvous datums
outbuf = same list of N PairRvous datums, routed to different procs
------------------------------------------------------------------------- */
void FixShake::ring_shake(int ndatum, char *cbuf, void *ptr)
int FixShake::rendezvous_shake(int n, char *inbuf,
int &flag, int *&proclist, char *&outbuf,
void *ptr)
{
FixShake *fsptr = (FixShake *)ptr;
int i,j,m;
FixShake *fsptr = (FixShake *) ptr;
Atom *atom = fsptr->atom;
int nlocal = atom->nlocal;
Memory *memory = fsptr->memory;
int *shake_flag = fsptr->shake_flag;
tagint **shake_atom = fsptr->shake_atom;
int **shake_type = fsptr->shake_type;
// clear atom map so it can be here as a hash table
// faster than an STL map for large atom counts
tagint *buf = (tagint *) cbuf;
int m;
atom->map_clear();
for (int i = 0; i < ndatum; i += 9) {
m = atom->map(buf[i]);
if (m >= 0 && m < nlocal) {
shake_flag[m] = buf[i+1];
shake_atom[m][0] = buf[i+2];
shake_atom[m][1] = buf[i+3];
shake_atom[m][2] = buf[i+4];
shake_atom[m][3] = buf[i+5];
shake_type[m][0] = buf[i+6];
shake_type[m][1] = buf[i+7];
shake_type[m][2] = buf[i+8];
}
// hash atom IDs stored in rendezvous decomposition
int nrvous = fsptr->nrvous;
tagint *atomIDs = fsptr->atomIDs;
for (i = 0; i < nrvous; i++)
atom->map_one(atomIDs[i],i);
// proclist = owner of atomID in caller decomposition
// outbuf = info about owned atomID
ShakeInfo *in = (ShakeInfo *) inbuf;
int *procowner = fsptr->procowner;
memory->create(proclist,n,"shake:proclist");
for (i = 0; i < n; i++) {
m = atom->map(in[i].atomID);
proclist[i] = procowner[m];
}
outbuf = inbuf;
// re-create atom map
atom->map_init(0);
atom->nghost = 0;
atom->map_set();
// flag = 1: outbuf = inbuf;
flag = 1;
return n;
}
/* ----------------------------------------------------------------------

View File

@ -120,6 +120,11 @@ class FixShake : public Fix {
int nmol;
void find_clusters();
void atom_owners();
void partner_info(int *, tagint **, int **, int **, int **, int **);
void nshake_info(int *, tagint **, int **);
void shake_info(int *, tagint **, int **);
int masscheck(double);
void unconstrained_update();
void unconstrained_update_respa(int);
@ -131,12 +136,40 @@ class FixShake : public Fix {
int bondtype_findset(int, tagint, tagint, int);
int angletype_findset(int, tagint, tagint, int);
// static variable for ring communication callback to access class data
// callback functions for ring communication
// data used by rendezvous callback methods
static void ring_bonds(int, char *, void *);
static void ring_nshake(int, char *, void *);
static void ring_shake(int, char *, void *);
int nrvous;
tagint *atomIDs;
int *procowner;
struct IDRvous {
int me;
tagint atomID;
};
struct PartnerInfo {
tagint atomID,partnerID;
int mask,type,massflag,bondtype;
};
struct NShakeInfo {
tagint atomID,partnerID;
int nshake;
};
struct ShakeInfo {
tagint atomID;
int shake_flag;
int shake_atom[4];
int shake_type[3];
};
// callback functions for rendezvous communication
static int rendezvous_ids(int, char *, int &, int *&, char *&, void *);
static int rendezvous_partners_info(int, char *, int &, int *&, char *&, void *);
static int rendezvous_nshake(int, char *, int &, int *&, char *&, void *);
static int rendezvous_shake(int, char *, int &, int *&, char *&, void *);
};
}

View File

@ -21,7 +21,6 @@
#include "modify.h"
#include "fix.h"
#include "accelerator_kokkos.h"
#include "hashlittle.h"
#include "atom_masks.h"
#include "memory.h"
#include "error.h"
@ -177,25 +176,20 @@ void Special::atom_owners()
// input datums = pairs of bonded atoms
// owning proc for each datum = random hash of atomID
// one datum for each owned atom: datum = owning proc, atomID
// one datum for each bond partner: datum = atomID, bond partner ID
// add inverted datum when netwon_bond on
for (int i = 0; i < nlocal; i++) {
//proc = hashlittle(&tag[i],sizeof(tagint),0) % nprocs;
proclist[i] = tag[i] % nprocs;
idbuf[i].me = me;
idbuf[i].atomID = tag[i];
}
// perform rendezvous operation
// each proc owns random subset of atoms
// receives all info to form and return their onetwo lists
// each proc assigned every 1/Pth atom
char *buf;
comm->rendezvous(nlocal,proclist,
(char *) idbuf,sizeof(PairRvous),
rendezvous_ids,buf,sizeof(PairRvous),
(void *) this);
(char *) idbuf,sizeof(IDRvous),
rendezvous_ids,buf,0,(void *) this);
memory->destroy(proclist);
memory->sfree(idbuf);
@ -215,49 +209,45 @@ void Special::onetwo_build_newton()
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
// ncount = # of my datums to send
// include nlocal datums with owner of each atom
// nsend = # of my datums to send
int ncount = 0;
int nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < num_bond[i]; j++) {
m = atom->map(bond_atom[i][j]);
if (m < 0 || m >= nlocal) ncount++;
if (m < 0 || m >= nlocal) nsend++;
}
}
int *proclist;
memory->create(proclist,ncount,"special:proclist");
memory->create(proclist,nsend,"special:proclist");
PairRvous *inbuf = (PairRvous *)
memory->smalloc((bigint) ncount*sizeof(PairRvous),"special:inbuf");
memory->smalloc((bigint) nsend*sizeof(PairRvous),"special:inbuf");
// setup input buf to rendezvous comm
// input datums = pairs of bonded atoms
// owning proc for each datum = random hash of atomID
// one datum for each owned atom: datum = owning proc, atomID
// one datum for each bond partner: datum = atomID, bond partner ID
// add inverted datum when netwon_bond on
// owning proc for each datum = atomID % nprocs
// one datum for each bond partner: bond partner ID, atomID
ncount = 0;
nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < num_bond[i]; j++) {
m = atom->map(bond_atom[i][j]);
if (m >= 0 && m < nlocal) continue;
proclist[ncount] = bond_atom[i][j] % nprocs;
inbuf[ncount].atomID = bond_atom[i][j];
inbuf[ncount].partnerID = tag[i];
ncount++;
proclist[nsend] = bond_atom[i][j] % nprocs;
inbuf[nsend].atomID = bond_atom[i][j];
inbuf[nsend].partnerID = tag[i];
nsend++;
}
}
// perform rendezvous operation
// each proc owns random subset of atoms
// receives all info to form and return their onetwo lists
char *buf;
int nreturn = comm->rendezvous(ncount,proclist,
int nreturn = comm->rendezvous(nsend,proclist,
(char *) inbuf,sizeof(PairRvous),
rendezvous_1234,buf,sizeof(PairRvous),
rendezvous_pairs,buf,sizeof(PairRvous),
(void *) this);
PairRvous *outbuf = (PairRvous *) buf;
@ -312,6 +302,28 @@ void Special::onetwo_build_newton()
void Special::onetwo_build_newton_off()
{
int i,j;
int *num_bond = atom->num_bond;
tagint **bond_atom = atom->bond_atom;
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
int max = 0;
for (i = 0; i < nlocal; i++)
max = MAX(max,num_bond[i]);
MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
memory->create(onetwo,nlocal,maxall,"special:onetwo");
// nsend = # of my datums to send
// include nlocal datums with owner of each atom
for (i = 0; i < nlocal; i++) {
nspecial[i][0] = num_bond[i];
for (j = 0; j < num_bond[i]; j++)
onetwo[i][j] = bond_atom[i][j];
}
}
/* ----------------------------------------------------------------------
@ -327,21 +339,20 @@ void Special::onethree_build()
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
// ncount = # of my datums to send
// include nlocal datums with owner of each atom
// nsend = # of my datums to send
int ncount = 0;
int nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < nspecial[i][0]; j++) {
m = atom->map(onetwo[i][j]);
if (m < 0 || m >= nlocal) ncount += nspecial[i][0]-1;
if (m < 0 || m >= nlocal) nsend += nspecial[i][0]-1;
}
}
int *proclist;
memory->create(proclist,ncount,"special:proclist");
memory->create(proclist,nsend,"special:proclist");
PairRvous *inbuf = (PairRvous *)
memory->smalloc((bigint) ncount*sizeof(PairRvous),"special:inbuf");
memory->smalloc((bigint) nsend*sizeof(PairRvous),"special:inbuf");
// setup input buf to rendezvous comm
// input datums = all pairs of onetwo atoms (they are 1-3 neighbors)
@ -349,7 +360,7 @@ void Special::onethree_build()
// one datum for each owned atom: datum = owning proc, atomID
// one datum for each onetwo pair: datum = atomID1, atomID2
ncount = 0;
nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < nspecial[i][0]; j++) {
m = atom->map(onetwo[i][j]);
@ -357,10 +368,10 @@ void Special::onethree_build()
proc = onetwo[i][j] % nprocs;
for (k = 0; k < nspecial[i][0]; k++) {
if (j == k) continue;
proclist[ncount] = proc;
inbuf[ncount].atomID = onetwo[i][j];
inbuf[ncount].partnerID = onetwo[i][k];
ncount++;
proclist[nsend] = proc;
inbuf[nsend].atomID = onetwo[i][j];
inbuf[nsend].partnerID = onetwo[i][k];
nsend++;
}
}
}
@ -370,9 +381,9 @@ void Special::onethree_build()
// receives all info to form and return their onethree lists
char *buf;
int nreturn = comm->rendezvous(ncount,proclist,
int nreturn = comm->rendezvous(nsend,proclist,
(char *) inbuf,sizeof(PairRvous),
rendezvous_1234,buf,sizeof(PairRvous),
rendezvous_pairs,buf,sizeof(PairRvous),
(void *) this);
PairRvous *outbuf = (PairRvous *) buf;
@ -434,21 +445,21 @@ void Special::onefour_build()
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
// ncount = # of my datums to send
// nsend = # of my datums to send
// include nlocal datums with owner of each atom
int ncount = 0;
int nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < nspecial[i][1]; j++) {
m = atom->map(onethree[i][j]);
if (m < 0 || m >= nlocal) ncount += nspecial[i][0];
if (m < 0 || m >= nlocal) nsend += nspecial[i][0];
}
}
int *proclist;
memory->create(proclist,ncount,"special:proclist");
memory->create(proclist,nsend,"special:proclist");
PairRvous *inbuf = (PairRvous *)
memory->smalloc((bigint) ncount*sizeof(PairRvous),"special:inbuf");
memory->smalloc((bigint) nsend*sizeof(PairRvous),"special:inbuf");
// setup input buf to rendezvous comm
// input datums = all pairs of onethree and onetwo atoms (they're 1-4 neighbors)
@ -456,17 +467,17 @@ void Special::onefour_build()
// one datum for each owned atom: datum = owning proc, atomID
// one datum for each onethree/onetwo pair: datum = atomID1, atomID2
ncount = 0;
nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < nspecial[i][1]; j++) {
m = atom->map(onethree[i][j]);
if (m >= 0 && m < nlocal) continue;
proc = onethree[i][j] % nprocs;
for (k = 0; k < nspecial[i][0]; k++) {
proclist[ncount] = proc;
inbuf[ncount].atomID = onethree[i][j];
inbuf[ncount].partnerID = onetwo[i][k];
ncount++;
proclist[nsend] = proc;
inbuf[nsend].atomID = onethree[i][j];
inbuf[nsend].partnerID = onetwo[i][k];
nsend++;
}
}
}
@ -476,9 +487,9 @@ void Special::onefour_build()
// receives all info to form and return their onefour lists
char *buf;
int nreturn = comm->rendezvous(ncount,proclist,
int nreturn = comm->rendezvous(nsend,proclist,
(char *) inbuf,sizeof(PairRvous),
rendezvous_1234,buf,sizeof(PairRvous),
rendezvous_pairs,buf,sizeof(PairRvous),
(void *) this);
PairRvous *outbuf = (PairRvous *) buf;
@ -773,7 +784,7 @@ void Special::combine()
void Special::angle_trim()
{
int i,j,m,n,proc,index;
int i,j,k,m;;
int *num_angle = atom->num_angle;
int *num_dihedral = atom->num_dihedral;
@ -804,96 +815,89 @@ void Special::angle_trim()
" %g = # of 1-3 neighbors before angle trim\n",allcount);
}
// if angles or dihedrals are defined,
// flag each 1-3 neigh if it appears in an angle or dihedral
// if angles or dihedrals are defined
// rendezvous angle 1-3 and dihedral 1-3,2-4 pairs
if ((num_angle && atom->nangles) || (num_dihedral && atom->ndihedrals)) {
// ncount = # of my datums to send in 3 parts for each owned atom
// proc owner, onethree list, angle end points
// angle end points are from angle list and 1-3 and 2-4 pairs in dihedrals
// latter is only for angles or dihedrlas where I own atom2
// nsend = # of my datums to send
// latter is only for angles or dihedrlas where I own atom2 (newton bond off)
int ncount = nlocal;
for (i = 0; i < nlocal; i++) ncount += nspecial[i][1];
int nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < num_angle[i]; j++) {
index = atom->map(angle_atom2[i][j]);
if (index >= 0 && index < nlocal) ncount += 2;
if (tag[i] != angle_atom2[i][j]) continue;
m = atom->map(angle_atom1[i][j]);
if (m < 0 || m >= nlocal) nsend++;
m = atom->map(angle_atom3[i][j]);
if (m < 0 || m >= nlocal) nsend++;
}
for (j = 0; j < num_dihedral[i]; j++) {
index = atom->map(dihedral_atom2[i][j]);
if (index >= 0 && index < nlocal) ncount += 4;
if (tag[i] != dihedral_atom2[i][j]) continue;
m = atom->map(dihedral_atom1[i][j]);
if (m < 0 || m >= nlocal) nsend++;
m = atom->map(dihedral_atom3[i][j]);
if (m < 0 || m >= nlocal) nsend++;
m = atom->map(dihedral_atom4[i][j]);
if (m < 0 || m >= nlocal) nsend++;
}
}
int *proclist;
memory->create(proclist,ncount,"special:proclist");
memory->create(proclist,nsend,"special:proclist");
PairRvous *inbuf = (PairRvous *)
memory->smalloc((bigint) ncount*sizeof(PairRvous),"special:inbuf");
memory->smalloc((bigint) nsend*sizeof(PairRvous),"special:inbuf");
// setup input buf to rendezvous comm
// one datum for each owned atom: datum = proc, atomID
// sent to owner of atomID
// one datum for each 1-4 partner: datum = atomID, ID
// sent to owner of atomID
// two datums for each dihedral 1-4 endatoms : datum = atomID, ID
// sent to owner of atomID
m = 0;
nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < nspecial[i][1]; j++) {
proclist[m] = proc;
//inbuf[m].me = -1;
inbuf[m].atomID = tag[i];
inbuf[m].partnerID = onethree[i][j];
m++;
}
for (j = 0; j < num_angle[i]; j++) {
index = atom->map(angle_atom2[i][j]);
if (index < 0 || index >= nlocal) continue;
if (tag[i] != angle_atom2[i][j]) continue;
proclist[m] = hashlittle(&angle_atom1[i][j],sizeof(tagint),0) % nprocs;
//inbuf[m].me = -2;
inbuf[m].atomID = angle_atom1[i][j];
inbuf[m].partnerID = angle_atom3[i][j];
m++;
m = atom->map(angle_atom1[i][j]);
if (m < 0 || m >= nlocal) {
proclist[nsend] = angle_atom1[i][j] % nprocs;
inbuf[nsend].atomID = angle_atom1[i][j];
inbuf[nsend].partnerID = angle_atom3[i][j];
nsend++;
}
proclist[m] = hashlittle(&angle_atom3[i][j],sizeof(tagint),0) % nprocs;
//inbuf[m].me = -2;
inbuf[m].atomID = angle_atom3[i][j];
inbuf[m].partnerID = angle_atom1[i][j];
m++;
m = atom->map(angle_atom3[i][j]);
if (m < 0 || m >= nlocal) {
proclist[nsend] = angle_atom3[i][j] % nprocs;
inbuf[nsend].atomID = angle_atom3[i][j];
inbuf[nsend].partnerID = angle_atom1[i][j];
nsend++;
}
}
for (j = 0; j < num_dihedral[i]; j++) {
index = atom->map(dihedral_atom2[i][j]);
if (index < 0 || index >= nlocal) continue;
if (tag[i] != dihedral_atom2[i][j]) continue;
proclist[m] = hashlittle(&dihedral_atom1[i][j],sizeof(tagint),0) % nprocs;
//inbuf[m].me = -2;
inbuf[m].atomID = dihedral_atom1[i][j];
inbuf[m].partnerID = dihedral_atom3[i][j];
m++;
m = atom->map(dihedral_atom1[i][j]);
if (m < 0 || m >= nlocal) {
proclist[nsend] = dihedral_atom1[i][j] % nprocs;
inbuf[nsend].atomID = dihedral_atom1[i][j];
inbuf[nsend].partnerID = dihedral_atom3[i][j];
nsend++;
}
proclist[m] = hashlittle(&dihedral_atom2[i][j],sizeof(tagint),0) % nprocs;
//inbuf[m].me = -2;
inbuf[m].atomID = dihedral_atom2[i][j];
inbuf[m].partnerID = dihedral_atom4[i][j];
m++;
m = atom->map(dihedral_atom3[i][j]);
if (m < 0 || m >= nlocal) {
proclist[nsend] = dihedral_atom3[i][j] % nprocs;
inbuf[nsend].atomID = dihedral_atom3[i][j];
inbuf[nsend].partnerID = dihedral_atom1[i][j];
nsend++;
}
proclist[m] = hashlittle(&dihedral_atom3[i][j],sizeof(tagint),0) % nprocs;
//inbuf[m].me = -2;
inbuf[m].atomID = dihedral_atom3[i][j];
inbuf[m].partnerID = dihedral_atom1[i][j];
m++;
proclist[m] = hashlittle(&dihedral_atom4[i][j],sizeof(tagint),0) % nprocs;
//inbuf[m].me = -2;
inbuf[m].atomID = dihedral_atom4[i][j];
inbuf[m].partnerID = dihedral_atom2[i][j];
m++;
m = atom->map(dihedral_atom4[i][j]);
if (m < 0 || m >= nlocal) {
proclist[nsend] = dihedral_atom4[i][j] % nprocs;
inbuf[nsend].atomID = dihedral_atom4[i][j];
inbuf[nsend].partnerID = dihedral_atom2[i][j];
nsend++;
}
}
}
@ -903,26 +907,112 @@ void Special::angle_trim()
// when done: each atom has atom ID of owning atom of its body
char *buf;
int nreturn = comm->rendezvous(ncount,proclist,
int nreturn = comm->rendezvous(nsend,proclist,
(char *) inbuf,sizeof(PairRvous),
rendezvous_trim,buf,sizeof(PairRvous),
rendezvous_pairs,buf,sizeof(PairRvous),
(void *) this);
PairRvous *outbuf = (PairRvous *) buf;
memory->destroy(proclist);
memory->sfree(inbuf);
// reset nspecial[1] and onethree for all owned atoms based on output info
// flag all onethree atoms to keep
for (i = 0; i < nlocal; i++) nspecial[i][1] = 0;
int max = 0;
for (i = 0; i < nlocal; i++)
max = MAX(max,nspecial[i][1]);
MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
int **flag;
memory->create(flag,nlocal,maxall,"special:flag");
for (i = 0; i < nlocal; i++)
for (j = 0; j < nspecial[i][1]; j++)
flag[i][j] = 0;
// reset nspecial[1] and onethree for all owned atoms based on output info
for (i = 0; i < nlocal; i++) {
for (j = 0; j < num_angle[i]; j++) {
if (tag[i] != angle_atom2[i][j]) continue;
m = atom->map(angle_atom1[i][j]);
if (m >= 0 && m < nlocal) {
for (k = 0; k < nspecial[m][1]; k++)
if (onethree[m][k] == angle_atom3[i][j]) {
flag[m][k] = 1;
break;
}
}
m = atom->map(angle_atom3[i][j]);
if (m >= 0 && m < nlocal) {
for (k = 0; k < nspecial[m][1]; k++)
if (onethree[m][k] == angle_atom1[i][j]) {
flag[m][k] = 1;
break;
}
}
}
for (j = 0; j < num_dihedral[i]; j++) {
if (tag[i] != dihedral_atom2[i][j]) continue;
m = atom->map(dihedral_atom1[i][j]);
if (m >= 0 && m < nlocal) {
for (k = 0; k < nspecial[m][1]; k++)
if (onethree[m][k] == dihedral_atom3[i][j]) {
flag[m][k] = 1;
break;
}
}
m = atom->map(dihedral_atom3[i][j]);
if (m >= 0 && m < nlocal) {
for (k = 0; k < nspecial[m][1]; k++)
if (onethree[m][k] == dihedral_atom1[i][j]) {
flag[m][k] = 1;
break;
}
}
m = atom->map(dihedral_atom4[i][j]);
if (m >= 0 && m < nlocal) {
for (k = 0; k < nspecial[m][1]; k++)
if (onethree[m][k] == dihedral_atom2[i][j]) {
flag[m][k] = 1;
break;
}
}
}
}
for (m = 0; m < nreturn; m++) {
i = atom->map(outbuf[m].atomID);
onethree[i][nspecial[i][1]++] = outbuf[m].partnerID;
for (k = 0; k < nspecial[i][1]; k++)
if (onethree[i][k] == outbuf[m].partnerID) {
flag[i][k] = 1;
break;
}
}
memory->destroy(outbuf);
// use flag values to compress onefour list for each atom
for (i = 0; i < nlocal; i++) {
j = 0;
while (j < nspecial[i][1]) {
if (flag[i][j] == 0) {
onethree[i][j] = onethree[i][nspecial[i][1]-1];
flag[i][j] = flag[i][nspecial[i][1]-1];
nspecial[i][1]--;
} else j++;
}
}
memory->destroy(flag);
// if no angles or dihedrals are defined, delete all 1-3 neighs
} else {
@ -952,7 +1042,7 @@ void Special::angle_trim()
void Special::dihedral_trim()
{
int i,j,m,n,proc,index;
int i,j,k,m;
int *num_dihedral = atom->num_dihedral;
tagint **dihedral_atom1 = atom->dihedral_atom1;
@ -978,68 +1068,51 @@ void Special::dihedral_trim()
" %g = # of 1-4 neighbors before dihedral trim\n",allcount);
}
// if dihedrals are defined, rendezvous onefour list with dihedral 1-4 pairs
// if dihedrals are defined, rendezvous dihedral 1-4 pairs
if (num_dihedral && atom->ndihedrals) {
// ncount = # of my datums to send in 3 parts for each owned atom
// onefour list, proc owner, dihedral end points
// latter is only for dihedrals where I own atom2
// nsend = # of my datums to send
// latter is only for dihedrals where I own atom2 (newton bond off)
int ncount = nlocal;
for (i = 0; i < nlocal; i++) ncount += nspecial[i][2];
int nsend = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < num_dihedral[i]; j++) {
index = atom->map(dihedral_atom2[i][j]);
if (index >= 0 && index < nlocal) ncount += 2;
if (tag[i] != dihedral_atom2[i][j]) continue;
m = atom->map(dihedral_atom1[i][j]);
if (m < 0 || m >= nlocal) nsend++;
m = atom->map(dihedral_atom4[i][j]);
if (m < 0 || m >= nlocal) nsend++;
}
}
int *proclist;
memory->create(proclist,ncount,"special:proclist");
memory->create(proclist,nsend,"special:proclist");
PairRvous *inbuf = (PairRvous *)
memory->smalloc((bigint) ncount*sizeof(PairRvous),"special:inbuf");
memory->smalloc((bigint) nsend*sizeof(PairRvous),"special:inbuf");
// setup input buf to rendezvous comm
// one datum for each owned atom: datum = proc, atomID
// sent to owner of atomID
// one datum for each 1-4 partner: datum = atomID, ID
// sent to owner of atomID
// two datums for each dihedral 1-4 endatoms : datum = atomID, ID
// sent to owner of atomID
m = 0;
nsend = 0;
for (i = 0; i < nlocal; i++) {
proc = hashlittle(&tag[i],sizeof(tagint),0) % nprocs;
proclist[m] = proc;
//inbuf[m].me = me;
inbuf[m].atomID = tag[i];
inbuf[m].partnerID = 0;
m++;
for (j = 0; j < nspecial[i][2]; j++) {
proclist[m] = proc;
//inbuf[m].me = -1;
inbuf[m].atomID = tag[i];
inbuf[m].partnerID = onefour[i][j];
m++;
}
for (j = 0; j < num_dihedral[i]; j++) {
index = atom->map(dihedral_atom2[i][j]);
if (index < 0 || index >= nlocal) continue;
if (tag[i] != dihedral_atom2[i][j]) continue;
proclist[m] = hashlittle(&dihedral_atom1[i][j],sizeof(tagint),0) % nprocs;
//inbuf[m].me = -2;
inbuf[m].atomID = dihedral_atom1[i][j];
inbuf[m].partnerID = dihedral_atom4[i][j];
m++;
m = atom->map(dihedral_atom1[i][j]);
if (m < 0 || m >= nlocal) {
proclist[nsend] = dihedral_atom1[i][j] % nprocs;
inbuf[nsend].atomID = dihedral_atom1[i][j];
inbuf[nsend].partnerID = dihedral_atom4[i][j];
nsend++;
}
proclist[m] = hashlittle(&dihedral_atom4[i][j],sizeof(tagint),0) % nprocs;
//inbuf[m].me = -2;
inbuf[m].atomID = dihedral_atom4[i][j];
inbuf[m].partnerID = dihedral_atom1[i][j];
m++;
m = atom->map(dihedral_atom4[i][j]);
if (m < 0 || m >= nlocal) {
proclist[nsend] = dihedral_atom4[i][j] % nprocs;
inbuf[nsend].atomID = dihedral_atom4[i][j];
inbuf[nsend].partnerID = dihedral_atom1[i][j];
nsend++;
}
}
}
@ -1049,26 +1122,81 @@ void Special::dihedral_trim()
// when done: each atom has atom ID of owning atom of its body
char *buf;
int nreturn = comm->rendezvous(ncount,proclist,
int nreturn = comm->rendezvous(nsend,proclist,
(char *) inbuf,sizeof(PairRvous),
rendezvous_trim,buf,sizeof(PairRvous),
rendezvous_pairs,buf,sizeof(PairRvous),
(void *) this);
PairRvous *outbuf = (PairRvous *) buf;
memory->destroy(proclist);
memory->sfree(inbuf);
// flag all onefour atoms to keep
int max = 0;
for (i = 0; i < nlocal; i++)
max = MAX(max,nspecial[i][2]);
MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
int **flag;
memory->create(flag,nlocal,maxall,"special:flag");
for (i = 0; i < nlocal; i++)
for (j = 0; j < nspecial[i][2]; j++)
flag[i][j] = 0;
// reset nspecial[2] and onefour for all owned atoms based on output info
for (i = 0; i < nlocal; i++) nspecial[i][2] = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < num_dihedral[i]; j++) {
if (tag[i] != dihedral_atom2[i][j]) continue;
m = atom->map(dihedral_atom1[i][j]);
if (m >= 0 && m < nlocal) {
for (k = 0; k < nspecial[m][2]; k++)
if (onefour[m][k] == dihedral_atom4[i][j]) {
flag[m][k] = 1;
break;
}
}
m = atom->map(dihedral_atom4[i][j]);
if (m >= 0 && m < nlocal) {
for (k = 0; k < nspecial[m][2]; k++)
if (onefour[m][k] == dihedral_atom1[i][j]) {
flag[m][k] = 1;
break;
}
}
}
}
for (m = 0; m < nreturn; m++) {
i = atom->map(outbuf[m].atomID);
onefour[i][nspecial[i][2]++] = outbuf[m].partnerID;
for (k = 0; k < nspecial[i][2]; k++)
if (onefour[i][k] == outbuf[m].partnerID) {
flag[i][k] = 1;
break;
}
}
memory->destroy(outbuf);
// use flag values to compress onefour list for each atom
for (i = 0; i < nlocal; i++) {
j = 0;
while (j < nspecial[i][2]) {
if (flag[i][j] == 0) {
onefour[i][j] = onefour[i][nspecial[i][2]-1];
flag[i][j] = flag[i][nspecial[i][2]-1];
nspecial[i][2]--;
} else j++;
}
}
memory->destroy(flag);
// if no dihedrals are defined, delete all 1-4 neighs
} else {
@ -1093,8 +1221,8 @@ void Special::dihedral_trim()
/* ----------------------------------------------------------------------
process data for atoms assigned to me in rendezvous decomposition
inbuf = list of N PairRvous datums
outbuf = empty
inbuf = list of N IDRvous datums
no outbuf
------------------------------------------------------------------------- */
int Special::rendezvous_ids(int n, char *inbuf,
@ -1109,7 +1237,6 @@ int Special::rendezvous_ids(int n, char *inbuf,
memory->create(procowner,n,"special:procowner");
memory->create(atomIDs,n,"special:atomIDs");
// NOTE: when to free these vectors
IDRvous *in = (IDRvous *) inbuf;
@ -1120,13 +1247,12 @@ int Special::rendezvous_ids(int n, char *inbuf,
// store rendezvous data in Special class
sptr->ncount = n;
sptr->nrvous = n;
sptr->procowner = procowner;
sptr->atomIDs = atomIDs;
proclist = NULL;
outbuf = NULL;
// flag = 0: no 2nd irregular comm needed in comm->rendezvous
flag = 0;
return 0;
}
@ -1138,7 +1264,7 @@ int Special::rendezvous_ids(int n, char *inbuf,
outbuf = same list of N PairRvous datums, routed to different procs
------------------------------------------------------------------------- */
int Special::rendezvous_1234(int n, char *inbuf,
int Special::rendezvous_pairs(int n, char *inbuf,
int &flag, int *&proclist, char *&outbuf,
void *ptr)
{
@ -1153,10 +1279,10 @@ int Special::rendezvous_1234(int n, char *inbuf,
// hash atom IDs stored in rendezvous decomposition
int ncount = sptr->ncount;
int nrvous = sptr->nrvous;
tagint *atomIDs = sptr->atomIDs;
for (int i = 0; i < ncount; i++)
for (int i = 0; i < nrvous; i++)
atom->map_one(atomIDs[i],i);
// proclist = owner of atomID in caller decomposition
@ -1172,7 +1298,6 @@ int Special::rendezvous_1234(int n, char *inbuf,
}
outbuf = inbuf;
// NOTE: set out = in flag
// re-create atom map
@ -1180,148 +1305,12 @@ int Special::rendezvous_1234(int n, char *inbuf,
atom->nghost = 0;
atom->map_set();
// flag = 1: outbuf = inbuf
flag = 1;
return n;
}
/* ----------------------------------------------------------------------
process data for atoms assigned to me in rendezvous decomposition
inbuf = list of N PairRvous datums
create outbuf = list of Nout PairRvous datums
------------------------------------------------------------------------- */
int Special::rendezvous_trim(int n, char *inbuf,
int &flag, int *&proclist, char *&outbuf,
void *ptr)
{
int i,j,m;
/*
Special *sptr = (Special *) ptr;
Atom *atom = sptr->atom;
Memory *memory = sptr->memory;
// clear atom map so it can be here as a hash table
// faster than an STL map for large atom counts
atom->map_clear();
// initialize hash
// ncount = number of atoms assigned to me
// key = atom ID
// value = index into Ncount-length data structure
PairRvous *in = (PairRvous *) inbuf;
//std::map<tagint,int> hash;
tagint id;
int ncount = 0;
for (i = 0; i < n; i++)
if (in[i].me >= 0)
//hash[in[i].atomID] = ncount++;
atom->map_one(in[i].atomID,ncount++);
// procowner = caller proc that owns each atom
// atomID = ID of each rendezvous atom I own
// npartner = # of 1-3 partners for each atom I own
int *procowner,*npartner;
tagint *atomID;
memory->create(procowner,ncount,"special:procowner");
memory->create(atomID,ncount,"special:atomID");
memory->create(npartner,ncount,"special:npartner");
for (m = 0; m < ncount; m++) npartner[m] = 0;
for (i = 0; i < n; i++) {
//m = hash.find(in[i].atomID)->second;
m = atom->map(in[i].atomID);
if (in[i].me >= 0) {
procowner[m] = in[i].me;
atomID[m] = in[i].atomID;
} else if (in[i].me == -1) npartner[m]++;
}
int max = 0;
for (m = 0; m < ncount; m++) max = MAX(max,npartner[m]);
// partner = list of 1-3 or 1-4 partners for each atom I own
int **partner;
memory->create(partner,ncount,max,"special:partner");
for (m = 0; m < ncount; m++) npartner[m] = 0;
for (i = 0; i < n; i++) {
if (in[i].me >= 0 || in[i].me == -2) continue;
//m = hash.find(in[i].atomID)->second;
m = atom->map(in[i].atomID);
partner[m][npartner[m]++] = in[i].partnerID;
}
// flag = 1 if partner is in an actual angle or in a dihedral
int **flag;
memory->create(flag,ncount,max,"special:flag");
for (i = 0; i < ncount; i++)
for (j = 0; j < npartner[i]; j++)
flag[i][j] = 0;
tagint actual;
for (i = 0; i < n; i++) {
if (in[i].me != -2) continue;
actual = in[i].partnerID;
//m = hash.find(in[i].atomID)->second;
m = atom->map(in[i].atomID);
for (j = 0; j < npartner[m]; j++)
if (partner[m][j] == actual) {
flag[m][j] = 1;
break;
}
}
// pass list of PairRvous datums back to comm->rendezvous
int nout = 0;
for (m = 0; m < ncount; m++) nout += npartner[m];
memory->create(proclist,nout,"special:proclist");
PairRvous *out = (PairRvous *)
memory->smalloc((bigint) nout*sizeof(PairRvous),"special:out");
nout = 0;
for (m = 0; m < ncount; m++)
for (j = 0; j < npartner[m]; j++) {
if (flag[m][j] == 0) continue;
proclist[nout] = procowner[m];
out[nout].atomID = atomID[m];
out[nout].partnerID = partner[m][j];
nout++;
}
outbuf = (char *) out;
// clean up
// Comm::rendezvous will delete proclist and out (outbuf)
memory->destroy(procowner);
memory->destroy(atomID);
memory->destroy(npartner);
memory->destroy(partner);
memory->destroy(flag);
// re-create atom map
atom->map_init(0);
atom->nghost = 0;
atom->map_set();
*/
//return nout;
flag = 2;
return 0;
}
/* ----------------------------------------------------------------------
allow fixes to alter special list
currently, only fix drude does this

View File

@ -31,7 +31,7 @@ class Special : protected Pointers {
// data used by rendezvous callback methods
int ncount;
int nrvous;
tagint *atomIDs;
int *procowner;
@ -44,6 +44,8 @@ class Special : protected Pointers {
tagint atomID,partnerID;
};
// private methods
void atom_owners();
void onetwo_build_newton();
void onetwo_build_newton_off();
@ -60,8 +62,7 @@ class Special : protected Pointers {
// callback functions for rendezvous communication
static int rendezvous_ids(int, char *, int &, int *&, char *&, void *);
static int rendezvous_1234(int, char *, int &, int *&, char *&, void *);
static int rendezvous_trim(int, char *, int &, int *&, char *&, void *);
static int rendezvous_pairs(int, char *, int &, int *&, char *&, void *);
};
}