/* ---------------------------------------------------------------------- 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. ------------------------------------------------------------------------- */ #include "mpi.h" #include "string.h" #include "stdio.h" #include "fix_shear_history.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "force.h" #include "pair.h" #include "update.h" #include "modify.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace FixConst; /* ---------------------------------------------------------------------- */ FixShearHistory::FixShearHistory(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { restart_peratom = 1; create_attribute = 1; // perform initial allocation of atom-based arrays // register with atom class npartner = NULL; partner = NULL; shearpartner = NULL; grow_arrays(atom->nmax); atom->add_callback(0); atom->add_callback(1); ipage = NULL; dpage = NULL; pgsize = oneatom = 0; // initialize npartner to 0 so neighbor list creation is OK the 1st time int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) npartner[i] = 0; maxtouch = 0; } /* ---------------------------------------------------------------------- */ FixShearHistory::~FixShearHistory() { // unregister this fix so atom class doesn't invoke it any more atom->delete_callback(id,0); atom->delete_callback(id,1); // delete locally stored arrays memory->destroy(npartner); memory->sfree(partner); memory->sfree(shearpartner); delete [] ipage; delete [] dpage; } /* ---------------------------------------------------------------------- */ int FixShearHistory::setmask() { int mask = 0; mask |= PRE_EXCHANGE; mask |= MIN_PRE_EXCHANGE; return mask; } /* ---------------------------------------------------------------------- */ void FixShearHistory::init() { if (atom->tag_enable == 0) error->all(FLERR, "Pair style granular with history requires atoms have IDs"); int dim; computeflag = (int *) pair->extract("computeflag",dim); allocate_pages(); } /* ---------------------------------------------------------------------- create pages if first time or if neighbor pgsize/oneatom has changed note that latter could cause shear history info to be discarded ------------------------------------------------------------------------- */ void FixShearHistory::allocate_pages() { int create = 0; if (ipage == NULL) create = 1; if (pgsize != neighbor->pgsize) create = 1; if (oneatom != neighbor->oneatom) create = 1; if (create) { delete [] ipage; delete [] dpage; pgsize = neighbor->pgsize; oneatom = neighbor->oneatom; int nmypage = comm->nthreads; ipage = new MyPage[nmypage]; dpage = new MyPage[nmypage]; for (int i = 0; i < nmypage; i++) { ipage[i].init(oneatom,pgsize); dpage[i].init(oneatom,pgsize); } } } /* ---------------------------------------------------------------------- called by setup of run or minimize called by write_restart as input script command only invoke pre_exchange() if neigh list stores more current history info than npartner/partner arrays in this fix that will only be case if pair->compute() has been invoked since update of npartner/npartner this logic avoids 2 problems: run 100; write_restart; run 100 setup_pre_exchange is called twice (by write_restart and 2nd run setup) w/out a neighbor list being created in between read_restart; run 100 setup_pre_exchange called by run setup whacks restart shear history info ------------------------------------------------------------------------- */ void FixShearHistory::setup_pre_exchange() { if (*computeflag) pre_exchange(); *computeflag = 0; } /* ---------------------------------------------------------------------- copy shear partner info from neighbor lists to atom arrays so can be migrated or stored with atoms ------------------------------------------------------------------------- */ void FixShearHistory::pre_exchange() { int i,j,ii,jj,m,n,inum,jnum; int *ilist,*jlist,*numneigh,**firstneigh; int *touch,**firsttouch; double *shear,*allshear,**firstshear; // nlocal may include atoms added since last neigh build int nlocal = atom->nlocal; // zero npartner for all current atoms // clear 2 page data structures for (i = 0; i < nlocal; i++) npartner[i] = 0; ipage->reset(); dpage->reset(); // 1st loop over neighbor list // calculate npartner for each owned atom // nlocal_neigh = nlocal when neigh list was built, may be smaller than nlocal tagint *tag = atom->tag; NeighList *list = pair->list; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; firsttouch = list->listgranhistory->firstneigh; firstshear = list->listgranhistory->firstdouble; int nlocal_neigh = 0; if (inum) nlocal_neigh = ilist[inum-1] + 1; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jlist = firstneigh[i]; jnum = numneigh[i]; touch = firsttouch[i]; for (jj = 0; jj < jnum; jj++) { if (touch[jj]) { npartner[i]++; j = jlist[jj]; j &= NEIGHMASK; if (j < nlocal_neigh) npartner[j]++; } } } // get page chunks to store atom IDs and shear history for my atoms for (ii = 0; ii < inum; ii++) { i = ilist[ii]; n = npartner[i]; partner[i] = ipage->get(n); shearpartner[i] = dpage->get(n); if (partner[i] == NULL || shearpartner[i] == NULL) error->one(FLERR,"Shear history overflow, boost neigh_modify one"); } // 2nd loop over neighbor list // store atom IDs and shear history for my atoms // re-zero npartner to use as counter for all my atoms for (i = 0; i < nlocal; i++) npartner[i] = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jlist = firstneigh[i]; allshear = firstshear[i]; jnum = numneigh[i]; touch = firsttouch[i]; for (jj = 0; jj < jnum; jj++) { if (touch[jj]) { shear = &allshear[3*jj]; j = jlist[jj]; j &= NEIGHMASK; m = npartner[i]; partner[i][m] = tag[j]; shearpartner[i][m][0] = shear[0]; shearpartner[i][m][1] = shear[1]; shearpartner[i][m][2] = shear[2]; npartner[i]++; if (j < nlocal_neigh) { m = npartner[j]; partner[j][m] = tag[i]; shearpartner[j][m][0] = -shear[0]; shearpartner[j][m][1] = -shear[1]; shearpartner[j][m][2] = -shear[2]; npartner[j]++; } } } } // set maxtouch = max # of partners of any owned atom // bump up comm->maxexchange_fix if necessary maxtouch = 0; for (i = 0; i < nlocal; i++) maxtouch = MAX(maxtouch,npartner[i]); comm->maxexchange_fix = MAX(comm->maxexchange_fix,4*maxtouch+1); } /* ---------------------------------------------------------------------- */ void FixShearHistory::min_setup_pre_exchange() { if (*computeflag) pre_exchange(); *computeflag = 0; } /* ---------------------------------------------------------------------- */ void FixShearHistory::min_pre_exchange() { pre_exchange(); } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixShearHistory::memory_usage() { int nmax = atom->nmax; double bytes = nmax * sizeof(int); bytes += nmax * sizeof(int *); bytes += nmax * sizeof(double *); int nmypage = comm->nthreads; for (int i = 0; i < nmypage; i++) { bytes += ipage[i].size(); bytes += dpage[i].size(); } return bytes; } /* ---------------------------------------------------------------------- allocate local atom-based arrays ------------------------------------------------------------------------- */ void FixShearHistory::grow_arrays(int nmax) { memory->grow(npartner,nmax,"shear_history:npartner"); partner = (tagint **) memory->srealloc(partner,nmax*sizeof(tagint *), "shear_history:partner"); typedef double (*sptype)[3]; shearpartner = (sptype *) memory->srealloc(shearpartner,nmax*sizeof(sptype), "shear_history:shearpartner"); } /* ---------------------------------------------------------------------- copy values within local atom-based arrays ------------------------------------------------------------------------- */ void FixShearHistory::copy_arrays(int i, int j, int delflag) { // just copy pointers for partner and shearpartner // b/c can't overwrite chunk allocation inside ipage,dpage // incoming atoms in unpack_exchange just grab new chunks // so are orphaning chunks for migrating atoms // OK, b/c will reset ipage,dpage on next reneighboring npartner[j] = npartner[i]; partner[j] = partner[i]; shearpartner[j] = shearpartner[i]; } /* ---------------------------------------------------------------------- initialize one atom's array values, called when atom is created ------------------------------------------------------------------------- */ void FixShearHistory::set_arrays(int i) { npartner[i] = 0; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for exchange with another proc ------------------------------------------------------------------------- */ int FixShearHistory::pack_exchange(int i, double *buf) { // NOTE: how do I know comm buf is big enough if extreme # of touching neighs // Comm::BUFEXTRA may need to be increased int m = 0; buf[m++] = npartner[i]; for (int n = 0; n < npartner[i]; n++) { buf[m++] = partner[i][n]; buf[m++] = shearpartner[i][n][0]; buf[m++] = shearpartner[i][n][1]; buf[m++] = shearpartner[i][n][2]; } return m; } /* ---------------------------------------------------------------------- unpack values in local atom-based arrays from exchange with another proc ------------------------------------------------------------------------- */ int FixShearHistory::unpack_exchange(int nlocal, double *buf) { // allocate new chunks from ipage,dpage for incoming values int m = 0; npartner[nlocal] = static_cast (buf[m++]); maxtouch = MAX(maxtouch,npartner[nlocal]); partner[nlocal] = ipage->get(npartner[nlocal]); shearpartner[nlocal] = dpage->get(npartner[nlocal]); for (int n = 0; n < npartner[nlocal]; n++) { partner[nlocal][n] = static_cast (buf[m++]); shearpartner[nlocal][n][0] = buf[m++]; shearpartner[nlocal][n][1] = buf[m++]; shearpartner[nlocal][n][2] = buf[m++]; } return m; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for restart file ------------------------------------------------------------------------- */ int FixShearHistory::pack_restart(int i, double *buf) { int m = 0; buf[m++] = 4*npartner[i] + 2; buf[m++] = npartner[i]; for (int n = 0; n < npartner[i]; n++) { buf[m++] = partner[i][n]; buf[m++] = shearpartner[i][n][0]; buf[m++] = shearpartner[i][n][1]; buf[m++] = shearpartner[i][n][2]; } return m; } /* ---------------------------------------------------------------------- unpack values from atom->extra array to restart the fix ------------------------------------------------------------------------- */ void FixShearHistory::unpack_restart(int nlocal, int nth) { // ipage = NULL if being called from granular pair style init() if (ipage == NULL) allocate_pages(); // skip to Nth set of extra values double **extra = atom->extra; int m = 0; for (int i = 0; i < nth; i++) m += static_cast (extra[nlocal][m]); m++; // allocate new chunks from ipage,dpage for incoming values npartner[nlocal] = static_cast (extra[nlocal][m++]); maxtouch = MAX(maxtouch,npartner[nlocal]); partner[nlocal] = ipage->get(npartner[nlocal]); shearpartner[nlocal] = dpage->get(npartner[nlocal]); for (int n = 0; n < npartner[nlocal]; n++) { partner[nlocal][n] = static_cast (extra[nlocal][m++]); shearpartner[nlocal][n][0] = extra[nlocal][m++]; shearpartner[nlocal][n][1] = extra[nlocal][m++]; shearpartner[nlocal][n][2] = extra[nlocal][m++]; } } /* ---------------------------------------------------------------------- maxsize of any atom's restart data ------------------------------------------------------------------------- */ int FixShearHistory::maxsize_restart() { // maxtouch_all = max # of touching partners across all procs int maxtouch_all; MPI_Allreduce(&maxtouch,&maxtouch_all,1,MPI_INT,MPI_MAX,world); return 4*maxtouch_all + 2; } /* ---------------------------------------------------------------------- size of atom nlocal's restart data ------------------------------------------------------------------------- */ int FixShearHistory::size_restart(int nlocal) { return 4*npartner[nlocal] + 2; }