diff --git a/src/USER-REAXC/fix_qeq_reax.cpp b/src/USER-REAXC/fix_qeq_reax.cpp index ba96d7b211..6323d5138a 100644 --- a/src/USER-REAXC/fix_qeq_reax.cpp +++ b/src/USER-REAXC/fix_qeq_reax.cpp @@ -322,13 +322,14 @@ void FixQEqReax::init() error->all(FLERR,"Must use pair_style reax/c with fix qeq/reax"); // need a half neighbor list w/ Newton off and ghost neighbors - // built whenever re-neighboring occurs + // make it occasional if QeQ not performed every timestep int irequest = neighbor->request(this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->fix = 1; neighbor->requests[irequest]->newton = 2; neighbor->requests[irequest]->ghost = 1; + if (nevery) neighbor->requests[irequest]->occasional = 1; init_shielding(); init_taper(); @@ -523,12 +524,14 @@ void FixQEqReax::compute_H() tagint *tag = atom->tag; x = atom->x; + if (nevery > 1) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // fill in the H matrix + m_fill = 0; r_sqr = 0; for( ii = 0; ii < inum; ii++ ) { diff --git a/src/delete_atoms.cpp b/src/delete_atoms.cpp index 2db870416a..2501917d85 100644 --- a/src/delete_atoms.cpp +++ b/src/delete_atoms.cpp @@ -266,8 +266,7 @@ void DeleteAtoms::delete_overlap(int narg, char **arg) error->all(FLERR,"Delete_atoms cutoff > neighbor cutoff"); // setup domain, communication and neighboring - // acquire ghosts - // build neighbor list based on earlier request + // acquire ghosts and build standard neighbor lists if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); @@ -277,6 +276,9 @@ void DeleteAtoms::delete_overlap(int narg, char **arg) comm->exchange(); comm->borders(); if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost); + neighbor->build(); + + // build neighbor list this command needs based on earlier request NeighList *list = neighbor->lists[irequest]; neighbor->build_one(irequest); diff --git a/src/neigh_full.cpp b/src/neigh_full.cpp index 9732d734f3..2eaf99d8e4 100644 --- a/src/neigh_full.cpp +++ b/src/neigh_full.cpp @@ -247,7 +247,7 @@ void Neighbor::full_bin(NeighList *list) // bin owned & ghost atoms - bin_atoms(); + if (binatomflag) bin_atoms(); double **x = atom->x; int *type = atom->type; @@ -355,7 +355,7 @@ void Neighbor::full_bin_ghost(NeighList *list) // bin owned & ghost atoms - bin_atoms(); + if (binatomflag) bin_atoms(); double **x = atom->x; int *type = atom->type; diff --git a/src/neigh_half_bin.cpp b/src/neigh_half_bin.cpp index 9bba2e6ef0..349deddae1 100644 --- a/src/neigh_half_bin.cpp +++ b/src/neigh_half_bin.cpp @@ -38,7 +38,7 @@ void Neighbor::half_bin_no_newton(NeighList *list) // bin local & ghost atoms - bin_atoms(); + if (binatomflag) bin_atoms(); double **x = atom->x; int *type = atom->type; @@ -151,7 +151,7 @@ void Neighbor::half_bin_no_newton_ghost(NeighList *list) // bin local & ghost atoms - bin_atoms(); + if (binatomflag) bin_atoms(); double **x = atom->x; int *type = atom->type; @@ -291,7 +291,7 @@ void Neighbor::half_bin_newton(NeighList *list) // bin local & ghost atoms - bin_atoms(); + if (binatomflag) bin_atoms(); double **x = atom->x; int *type = atom->type; @@ -433,7 +433,7 @@ void Neighbor::half_bin_newton_tri(NeighList *list) // bin local & ghost atoms - bin_atoms(); + if (binatomflag) bin_atoms(); double **x = atom->x; int *type = atom->type; diff --git a/src/neigh_list.cpp b/src/neigh_list.cpp index 24570258de..dc925a6f90 100644 --- a/src/neigh_list.cpp +++ b/src/neigh_list.cpp @@ -42,6 +42,8 @@ NeighList::NeighList(LAMMPS *lmp) : dnum = 0; + last_build = -1; + iskip = NULL; ijskip = NULL; diff --git a/src/neigh_list.h b/src/neigh_list.h index 0329c14040..f7fecce9b8 100644 --- a/src/neigh_list.h +++ b/src/neigh_list.h @@ -45,6 +45,8 @@ class NeighList : protected Pointers { MyPage *ipage; // pages of neighbor indices MyPage *dpage; // pages of neighbor doubles, if dnum > 0 + bigint last_build; // timestep of last build for occasional lists + // atom types to skip when building list // iskip,ijskip are just ptrs to corresponding request diff --git a/src/neigh_respa.cpp b/src/neigh_respa.cpp index 91f85de6ea..777534746b 100644 --- a/src/neigh_respa.cpp +++ b/src/neigh_respa.cpp @@ -378,7 +378,7 @@ void Neighbor::respa_bin_no_newton(NeighList *list) // bin local & ghost atoms - bin_atoms(); + if (binatomflag) bin_atoms(); double **x = atom->x; int *type = atom->type; @@ -548,7 +548,7 @@ void Neighbor::respa_bin_newton(NeighList *list) // bin local & ghost atoms - bin_atoms(); + if (binatomflag) bin_atoms(); double **x = atom->x; int *type = atom->type; @@ -765,7 +765,7 @@ void Neighbor::respa_bin_newton_tri(NeighList *list) // bin local & ghost atoms - bin_atoms(); + if (binatomflag) bin_atoms(); double **x = atom->x; int *type = atom->type; diff --git a/src/neighbor.cpp b/src/neighbor.cpp index bc96075dd9..c38d8db7aa 100644 --- a/src/neighbor.cpp +++ b/src/neighbor.cpp @@ -83,6 +83,7 @@ Neighbor::Neighbor(LAMMPS *lmp) : Pointers(lmp) binsizeflag = 0; build_once = 0; cluster_check = 0; + binatomflag = 1; cutneighsq = NULL; cutneighghostsq = NULL; @@ -508,27 +509,6 @@ void Neighbor::init() // detect lists that are connected to other lists // if-then-else sequence and processed flag is important // since don't want to re-process skip or copy lists further down - // skip list needs to have granhistory or respa info added - // copy: point this list at request->otherlist, could be a skip list - // skip: point this list at request->otherlist, copy skip info from request - // also set granular and respa info if applicable - // half_from_full: point this list at preceeding full list - // granhistory: set preceeding list's listgranhistory to this list - // also set preceeding list's ptr to FixShearHistory - // respaouter: point this list at preceeding 1/2 inner/middle lists - // pair and half: if there is a full non-occasional non-skip list - // change this list to half_from_full and point at the full list - // parent could be copy list or pair or fix - // fix/compute requests: - // whether request is occasional or not doesn't matter - // if request = half and non-skip pair half/respaouter exists, - // become copy of that list if cudable flag matches - // if request = full and non-skip pair full exists, - // become copy of that list if cudable flag matches - // if request = half and non-skip pair full exists, - // become half_from_full of that list if cudable flag matches - // if no matches, do nothing, fix/compute list will be built directly - // ok if parent is copy list int processed; @@ -536,20 +516,32 @@ void Neighbor::init() if (!lists[i]) continue; processed = 0; + // copy: point this list at request->otherlist, could be a skip list + if (requests[i]->copy) { lists[i]->listcopy = lists[requests[i]->otherlist]; processed = 1; + // skip: point this list at request->otherlist, + // copy skip info from request + // skip list still needs to have granhistory or respa info added below + } else if (requests[i]->skip) { lists[i]->listskip = lists[requests[i]->otherlist]; lists[i]->copy_skip_info(requests[i]->iskip,requests[i]->ijskip); processed = 1; + // half_from_full: point this list at full list that comes right before + // will only be case if pair style requested one after other + } else if (requests[i]->half_from_full) { lists[i]->listfull = lists[i-1]; processed = 1; } + // granhistory: set preceeding list's listgranhistory to this list + // also set preceeding list's ptr to FixShearHistory + if (requests[i]->granhistory) { lists[i-1]->listgranhistory = lists[i]; for (int ifix = 0; ifix < modify->nfix; ifix++) @@ -557,6 +549,8 @@ void Neighbor::init() lists[i-1]->fix_history = (FixShearHistory *) modify->fix[ifix]; processed = 1; + // respaouter: point this list at preceeding 1/2 inner/middle lists + } else if (requests[i]->respaouter) { if (requests[i-1]->respainner) { lists[i]->respamiddle = 0; @@ -571,6 +565,10 @@ void Neighbor::init() if (processed) continue; + // pair and half: if there is a full non-occasional non-skip list + // change this list to half_from_full and point at the full list + // parent could be copy list or pair or fix + if (requests[i]->pair && requests[i]->half) { for (j = 0; j < nrequest; j++) { if (!lists[j]) continue; @@ -583,6 +581,18 @@ void Neighbor::init() lists[i]->listfull = lists[j]; } + // fix/compute requests: + // whether request is occasional or not doesn't matter + // if request = half and non-skip pair half/respaouter exists, + // become copy of that list if cudable flag matches + // if request = full and non-skip pair full exists, + // become copy of that list if cudable flag matches + // if request = half and non-skip pair full exists, + // become half_from_full of that list if cudable flag matches + // if no matches, do nothing + // fix/compute list will be built independently as needed + // ok if parent is itself a copy list + } else if (requests[i]->fix || requests[i]->compute) { for (j = 0; j < nrequest; j++) { if (!lists[j]) continue; @@ -1349,8 +1359,8 @@ int Neighbor::check_distance() } /* ---------------------------------------------------------------------- - build all perpetual neighbor lists every few timesteps - pairwise & topology lists are created as needed + build perpetuals neighbor lists + called at setup and every few timesteps during run or minimization topology lists only built if topoflag = 1, USER-CUDA calls with topoflag = 0 ------------------------------------------------------------------------- */ @@ -1419,12 +1429,12 @@ void Neighbor::build(int topoflag) memory->create(bins,maxbin,"bins"); } - // check that neighbor list with special bond flags will not overflow + // check that using special bond flags will not overflow neigh lists if (atom->nlocal+atom->nghost > NEIGHMASK) error->one(FLERR,"Too many local+ghost atoms for neighbor list"); - // invoke building of pair and molecular neighbor lists + // invoke building of pair and molecular topology neighbor lists // only for pairwise lists with buildflag set // blist is for standard neigh lists, otherwise is a Kokkos list @@ -1455,9 +1465,22 @@ void Neighbor::build_topology() called by other classes ------------------------------------------------------------------------- */ -void Neighbor::build_one(int i) +void Neighbor::build_one(int i, int preflag) { - // update stencils and grow atom arrays and bins as needed + // no need to build if already built since last re-neighbor + // preflag is set by fix bond/create and fix bond/swap + // b/c they invoke build_one() on same step neigh list is re-built, + // but before re-build, so need to use ">" instead of ">=" + + if (preflag) { + if (lists[i]->last_build > lastcall) return; + } else { + if (lists[i]->last_build >= lastcall) return; + } + + lists[i]->last_build = update->ntimestep; + + // update stencils and grow atom arrays as needed // only for relevant settings of stencilflag and growflag // grow atom array for this list to current size of perpetual lists @@ -1468,42 +1491,14 @@ void Neighbor::build_one(int i) if (lists[i]->growflag) lists[i]->grow(maxatom); - // extend atom bin list if necessary - - if (style != NSQ && atom->nmax > maxbin) { - maxbin = atom->nmax; - memory->destroy(bins); - memory->create(bins,maxbin,"bins"); - } - - // check that neighbor list with special bond flags will not overflow - - if (atom->nlocal+atom->nghost > NEIGHMASK) - error->one(FLERR,"Too many local+ghost atoms for neighbor list"); - - // when occasional list built, LAMMPS can crash if atoms have moved too far - // why is this? maybe b/c this list is derived from some now out-of-date list? - // give warning if this is the case - // no easy workaround b/c all neighbor lists really need to be rebuilt - // solution is for input script to check more often for rebuild - // only check_distance if running a simulation, not between simulations - // comment out for now - // is sometimes giving warning when there is no issue - // e.g. when a variable uses a fix with an occasional neigh list - // at the beginning of a timestep (e.g. fix move) where - // all neigh lists are about to be re-built anyway - - /* - int flag = 0; - if (dist_check && update->whichflag) flag = check_distance(); - if (flag && me == 0) { - printf("BUILD ONE ERROR: %ld\n",update->ntimestep); - error->warning(FLERR,"Building an occasional neighbor list when " - "atoms may have moved too far"); - } - */ + // build list I, turning off atom binning + // binning results from last re-neighbor should be used instead + // if re-bin now, atoms may have moved outside of proc domain & bin extent, + // leading to errors or even a crash + binatomflag = 0; (this->*pair_build[i])(lists[i]); + binatomflag = 1; } /* ---------------------------------------------------------------------- diff --git a/src/neighbor.h b/src/neighbor.h index ec6881d56d..3c0c4af889 100644 --- a/src/neighbor.h +++ b/src/neighbor.h @@ -75,7 +75,7 @@ class Neighbor : protected Pointers { void setup_bins(); // setup bins based on box and cutoff virtual void build(int topoflag=1); // create all neighbor lists (pair,bond) virtual void build_topology(); // create all topology neighbor lists - void build_one(int); // create a single neighbor list + void build_one(int, int preflag=0); // create a single neighbor list void set(int, char **); // set neighbor style and skin distance void modify_params(int, char**); // modify parameters that control builds bigint memory_usage(); @@ -107,6 +107,9 @@ class Neighbor : protected Pointers { double boxlo_hold[3],boxhi_hold[3]; // box size at last neighbor build double corners_hold[8][3]; // box corners at last neighbor build + int binatomflag; // bin atoms or not when build neigh list + // turned off by build_one() + int nbinx,nbiny,nbinz; // # of global bins int *bins; // ptr to next atom in each bin int maxbin; // size of bins array