diff --git a/src/neigh_shardlow.cpp b/src/neigh_shardlow.cpp new file mode 100644 index 0000000000..0163e6eb4d --- /dev/null +++ b/src/neigh_shardlow.cpp @@ -0,0 +1,471 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: + James Larentzos and Timothy I. Mattox (Engility Corporation) +------------------------------------------------------------------------- */ + +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "atom.h" +#include "atom_vec.h" +#include "molecule.h" +#include "domain.h" +#include "group.h" +#include "memory.h" +#include "error.h" +#include "update.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- + convert atom coords into the ssa active interaction region number +------------------------------------------------------------------------- */ + +int Neighbor::coord2ssa_airnum(double *x) +{ + int ix, iy, iz; + + ix = iy = iz = 0; + if (x[2] < domain->sublo[2]) iz = -1; + if (x[2] > domain->subhi[2]) iz = 1; + if (x[1] < domain->sublo[1]) iy = -1; + if (x[1] > domain->subhi[1]) iy = 1; + if (x[0] < domain->sublo[0]) ix = -1; + if (x[0] > domain->subhi[0]) ix = 1; + + if(iz < 0) return 0; + + if(iz == 0){ + if( iy<0 ) return 0; // bottom left/middle/right + if( (iy==0) && (ix<0) ) return 0; // left atoms + if( (iy==0) && (ix==0) ) return 1; // Locally owned atoms + if( (iy==0) && (ix>0) ) return 3; // Right atoms + if( (iy>0) && (ix==0) ) return 2; // Top-middle atoms + if( (iy>0) && (ix!=0) ) return 4; // Top-right and top-left atoms + } else if(iz > 0) { + if((ix==0) && (iy==0)) return 5; // Back atoms + if((ix==0) && (iy!=0)) return 6; // Top-back and bottom-back atoms + if((ix!=0) && (iy==0)) return 7; // Left-back and right-back atoms + if((ix!=0) && (iy!=0)) return 8; // Back corner atoms + } + + return 0; +} + +/* ---------------------------------------------------------------------- + * assign owned and ghost atoms their ssa active interaction region numbers + * Called in the pre_neighbor and setup_pre_neighbor fix stages +------------------------------------------------------------------------- */ + +void Neighbor::assign_ssa_airnums() +{ + int i,ibin; + double **x = atom->x; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int nall = nlocal + atom->nghost; + + if (nall > len_ssa_airnum) { + len_ssa_airnum = nall; + memory->destroy(ssa_airnum); + memory->create(ssa_airnum,len_ssa_airnum,"ssa_airnum"); + } + + // bin in reverse order so linked list will be in forward order + + if (includegroup) { + int bitmask = group->bitmask[includegroup]; + for (i = nall-1; i >= nlocal; i--) { + if (mask[i] & bitmask) { + ibin = coord2ssa_airnum(x[i]); + } else { + ibin = 0; + } + ssa_airnum[i] = ibin; + } + // All the local excluded atoms are in the zero airnum + ibin = 0; + for (i = atom->nlocal-1; i >= atom->nfirst; i--) { + ssa_airnum[i] = ibin; + } + } else { + for (i = nall-1; i >= nlocal; i--) { + ibin = coord2ssa_airnum(x[i]); + ssa_airnum[i] = ibin; + } + } + + // All the local included atoms are in the same airnum (#1) + if (i >= 0) { + ibin = coord2ssa_airnum(x[i]); + do { + ssa_airnum[i] = ibin; + } while (--i >= 0); + } +} + +/* ---------------------------------------------------------------------- + routines to create a stencil = list of bin offsets + stencil = bins whose closest corner to central bin is within cutoff + sx,sy,sz = bin bounds = furthest the stencil could possibly extend + 3d creates xyz stencil, 2d creates xy stencil + for half list with newton on: + stencil is bins to the "upper right" of central bin + stencil does not include self +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- */ + +void Neighbor::stencil_half_bin_2d_ssa(NeighList *list, + int sx, int sy, int sz) +{ + int i,j; + int *stencil = list->stencil; + int nstencil = 0; + + for (j = 0; j <= sy; j++) + for (i = -sx; i <= sx; i++) + if (j > 0 || (j == 0 && i > 0)) + if (bin_distance(i,j,0) < cutneighmaxsq) + stencil[nstencil++] = j*mbinx + i; + + list->nstencil = nstencil; + + // Now include additional bins for AIR ghosts only + for (j = -sy; j <= 0; j++) + for (i = -sx; i <= sx; i++) { + if (j == 0 && i > 0) continue; + if (bin_distance(i,j,0) < cutneighmaxsq) + stencil[nstencil++] = j*mbinx + i; + } + + while (nstencil < list->maxstencil) { + stencil[nstencil++] = INT_MAX; + } +} + +/* ---------------------------------------------------------------------- */ + +void Neighbor::stencil_half_bin_3d_ssa(NeighList *list, + int sx, int sy, int sz) +{ + int i,j,k; + int *stencil = list->stencil; + int nstencil = 0; + + for (k = 0; k <= sz; k++) + for (j = -sy; j <= sy; j++) + for (i = -sx; i <= sx; i++) + if (k > 0 || j > 0 || (j == 0 && i > 0)) + if (bin_distance(i,j,k) < cutneighmaxsq) + stencil[nstencil++] = k*mbiny*mbinx + j*mbinx + i; + + list->nstencil = nstencil; + + // Now include additional bins for AIR ghosts only + for (k = -sz; k < 0; k++) + for (j = -sy; j <= sy; j++) + for (i = -sx; i <= sx; i++) + if (bin_distance(i,j,k) < cutneighmaxsq) + stencil[nstencil++] = k*mbiny*mbinx + j*mbinx + i; + k = 0; // skip already included bins at k == 0 + for (j = -sy; j <= 0; j++) + for (i = -sx; i <= sx; i++) { + if (j == 0 && i > 0) continue; + if (bin_distance(i,j,k) < cutneighmaxsq) + stencil[nstencil++] = k*mbiny*mbinx + j*mbinx + i; + } + + while (nstencil < list->maxstencil) { + stencil[nstencil++] = INT_MAX; + } +} + +/* ---------------------------------------------------------------------- + build half list from full list for use by Shardlow Spliting Algorithm + pair stored once if i,j are both owned and i < j + if j is ghost, only store if j coords are "above and to the right" of i + works if full list is a skip list +------------------------------------------------------------------------- */ + +void Neighbor::half_from_full_newton_ssa(NeighList *list) +{ + int i,j,ii,jj,n,jnum,joriginal; + int *neighptr,*jlist; + + int nlocal = atom->nlocal; + + int *ilist = list->ilist; + int *numneigh = list->numneigh; + int **firstneigh = list->firstneigh; + MyPage *ipage = list->ipage; + + int *ilist_full = list->listfull->ilist; + int *numneigh_full = list->listfull->numneigh; + int **firstneigh_full = list->listfull->firstneigh; + int inum_full = list->listfull->inum; + + int inum = 0; + ipage->reset(); + + // loop over parent full list + + for (ii = 0; ii < inum_full; ii++) { + n = 0; + neighptr = ipage->vget(); + + i = ilist_full[ii]; + + // loop over full neighbor list + + jlist = firstneigh_full[i]; + jnum = numneigh_full[i]; + + for (jj = 0; jj < jnum; jj++) { + joriginal = jlist[jj]; + j = joriginal & NEIGHMASK; + if (j < nlocal) { + if (i > j) continue; + } else { + if (ssa_airnum[j] <= 0) continue; + } + neighptr[n++] = joriginal; + } + + ilist[inum++] = i; + firstneigh[i] = neighptr; + numneigh[i] = n; + ipage->vgot(n); + if (ipage->status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); + } + + list->inum = inum; +} + +/* ---------------------------------------------------------------------- + for Shardlow Spliting Algorithm: + binned neighbor list construction with full Newton's 3rd law + each owned atom i checks its own bin and other bins in Newton stencil + every pair stored exactly once by some processor +------------------------------------------------------------------------- */ + +void Neighbor::half_bin_newton_ssa(NeighList *list) +{ + int i,j,k,n,itype,jtype,ibin,which,imol,iatom,moltemplate; + tagint tagprev; + double xtmp,ytmp,ztmp,delx,dely,delz,rsq; + int *neighptr; + + double **x = atom->x; + int *type = atom->type; + int *mask = atom->mask; + tagint *tag = atom->tag; + tagint *molecule = atom->molecule; + tagint **special = atom->special; + int **nspecial = atom->nspecial; + int nlocal = atom->nlocal; + int nall = nlocal + atom->nghost; + + int *molindex = atom->molindex; + int *molatom = atom->molatom; + Molecule **onemols = atom->avec->onemols; + int molecular = atom->molecular; + if (molecular == 2) moltemplate = 1; + else moltemplate = 0; + + int *ilist = list->ilist; + int *numneigh = list->numneigh; + int **firstneigh = list->firstneigh; + int nstencil = list->nstencil; + int maxstencil = list->maxstencil; + int *stencil = list->stencil; + MyPage *ipage = list->ipage; + + int inum = 0; + +/* ---------------------------------------------------------------------- + bin owned and ghost atoms for use by Shardlow Splitting Algorithm + exclude ghost atoms that are not in the Active Interaction Regions (AIR) +------------------------------------------------------------------------- */ + + if (mbins > maxhead_ssa) { + maxhead_ssa = mbins; + memory->destroy(gbinhead_ssa); + memory->destroy(binhead_ssa); + memory->create(binhead_ssa,maxhead_ssa,"binhead_ssa"); + memory->create(gbinhead_ssa,maxhead_ssa,"gbinhead_ssa"); + } + for (i = 0; i < mbins; i++) { + gbinhead_ssa[i] = -1; + binhead_ssa[i] = -1; + } + + if (maxbin > maxbin_ssa) { + maxbin_ssa = maxbin; + memory->destroy(bins_ssa); + memory->create(bins_ssa,maxbin_ssa,"bins_ssa"); + } + + // bin in reverse order so linked list will be in forward order + + if (includegroup) { + int bitmask = group->bitmask[includegroup]; + for (i = nall-1; i >= nlocal; i--) { + if (ssa_airnum[i] <= 0) continue; // skip ghost atoms not in AIR + if (mask[i] & bitmask) { + ibin = coord2bin(x[i]); + bins_ssa[i] = gbinhead_ssa[ibin]; + gbinhead_ssa[ibin] = i; + } + } + nlocal = atom->nfirst; // This is important for the code that follows! + } else { + for (i = nall-1; i >= nlocal; i--) { + if (ssa_airnum[i] <= 0) continue; // skip ghost atoms not in AIR + ibin = coord2bin(x[i]); + bins_ssa[i] = gbinhead_ssa[ibin]; + gbinhead_ssa[ibin] = i; + } + } + for (i = nlocal-1; i >= 0; i--) { + ibin = coord2bin(x[i]); + bins_ssa[i] = binhead_ssa[ibin]; + binhead_ssa[ibin] = i; + } + + ipage->reset(); + + // loop over owned atoms, storing half of the neighbors + + for (i = 0; i < nlocal; i++) { + n = 0; + neighptr = ipage->vget(); + + itype = type[i]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + if (moltemplate) { + imol = molindex[i]; + iatom = molatom[i]; + tagprev = tag[i] - iatom - 1; + } + + // loop over rest of local atoms in i's bin + // just store them, since j is beyond i in linked list + + for (j = bins_ssa[i]; j >= 0; j = bins_ssa[j]) { + + jtype = type[j]; + if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + + if (rsq <= cutneighsq[itype][jtype]) { + if (molecular) { + if (!moltemplate) + which = find_special(special[i],nspecial[i],tag[j]); + else if (imol >= 0) + which = find_special(onemols[imol]->special[iatom], + onemols[imol]->nspecial[iatom], + tag[j]-tagprev); + else which = 0; + if (which == 0) neighptr[n++] = j; + else if (domain->minimum_image_check(delx,dely,delz)) + neighptr[n++] = j; + else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; + } + } + + ibin = coord2bin(x[i]); + + // loop over all local atoms in other bins in "half" stencil + for (k = 0; k < nstencil; k++) { + for (j = binhead_ssa[ibin+stencil[k]]; j >= 0; j = bins_ssa[j]) { + + jtype = type[j]; + if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + + if (rsq <= cutneighsq[itype][jtype]) { + if (molecular) { + if (!moltemplate) + which = find_special(special[i],nspecial[i],tag[j]); + else if (imol >= 0) + which = find_special(onemols[imol]->special[iatom], + onemols[imol]->nspecial[iatom], + tag[j]-tagprev); + else which = 0; + if (which == 0) neighptr[n++] = j; + else if (domain->minimum_image_check(delx,dely,delz)) + neighptr[n++] = j; + else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; + } + } + } + + // loop over AIR ghost atoms in all bins in "full" stencil + // Note: the non-AIR ghost atoms have already been filtered out + for (k = 0; k < maxstencil; k++) { + if (stencil[k] > mbins) break; /* Check if ghost stencil bins are exhausted */ + for (j = gbinhead_ssa[ibin+stencil[k]]; j >= 0; j = bins_ssa[j]) { + + jtype = type[j]; + if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + + if (rsq <= cutneighsq[itype][jtype]) { + if (molecular) { + if (!moltemplate) + which = find_special(special[i],nspecial[i],tag[j]); + else if (imol >= 0) + which = find_special(onemols[imol]->special[iatom], + onemols[imol]->nspecial[iatom], + tag[j]-tagprev); + else which = 0; + if (which == 0) neighptr[n++] = j; + else if (domain->minimum_image_check(delx,dely,delz)) + neighptr[n++] = j; + else if (which > 0) neighptr[n++] = j ^ (which << SBBITS); + } else neighptr[n++] = j; + } + } + } + + ilist[inum++] = i; + firstneigh[i] = neighptr; + numneigh[i] = n; + ipage->vgot(n); + if (ipage->status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); + } + + list->inum = inum; +} diff --git a/src/neighbor.cpp b/src/neighbor.cpp index db28f6d309..e9ee23e37f 100644 --- a/src/neighbor.cpp +++ b/src/neighbor.cpp @@ -162,7 +162,6 @@ Neighbor::Neighbor(LAMMPS *lmp) : Pointers(lmp) improperlist = NULL; copymode = 0; - last_binning_timestep = -1; } /* ---------------------------------------------------------------------- */ @@ -2015,11 +2014,6 @@ void Neighbor::bin_atoms() { int i,ibin; - // NOTE: added for USER-DPD, why do we need this? - - //if (last_binning_timestep == update->ntimestep) return; - //last_binning_timestep = update->ntimestep; - for (i = 0; i < mbins; i++) binhead[i] = -1; // bin in reverse order so linked list will be in forward order diff --git a/src/neighbor.h b/src/neighbor.h index 8059e699bf..deba569916 100644 --- a/src/neighbor.h +++ b/src/neighbor.h @@ -71,7 +71,7 @@ class Neighbor : protected Pointers { int cluster_check; // 1 if check bond/angle/etc satisfies minimg - // USER-DPD package - better to make this private? + // USER-DPD package int *ssa_airnum; // AIR number of each atom for SSA in USER-DPD @@ -121,7 +121,6 @@ class Neighbor : protected Pointers { int binatomflag; // bin atoms or not when build neigh list // turned off by build_one() - bigint last_binning_timestep; // last step neighbor binning was done int nbinx,nbiny,nbinz; // # of global bins int *bins; // ptr to next atom in each bin @@ -180,7 +179,12 @@ class Neighbor : protected Pointers { // USER-DPD package - int len_ssa_airnum; // length of ssa_airnum array + int len_ssa_airnum; // length of ssa_airnum array + int *bins_ssa; // ptr to next atom in each bin used by SSA + int maxbin_ssa; // size of bins array used by SSA + int *binhead_ssa; // ptr to 1st atom in each bin used by SSA + int *gbinhead_ssa; // ptr to 1st ghost atom in each bin used by SSA + int maxhead_ssa; // size of binhead array used by SSA // methods @@ -320,13 +324,13 @@ class Neighbor : protected Pointers { // SSA neighboring for USER-DPD - //int coord2ssa_airnum(double *); // map atom coord to an AIR number - //void assign_ssa_airnums(); // set ssa_airnum values + int coord2ssa_airnum(double *); // map atom coord to an AIR number + void assign_ssa_airnums(); // set ssa_airnum values - void half_bin_newton_ssa(NeighList *) {} - void half_from_full_newton_ssa(class NeighList *) {} - void stencil_half_bin_2d_ssa(class NeighList *, int, int, int) {} - void stencil_half_bin_3d_ssa(class NeighList *, int, int, int) {} + void half_bin_newton_ssa(NeighList *); + void half_from_full_newton_ssa(class NeighList *); + void stencil_half_bin_2d_ssa(class NeighList *, int, int, int); + void stencil_half_bin_3d_ssa(class NeighList *, int, int, int); // find_special: determine if atom j is in special list of atom i // if it is not, return 0