Files
lammps/src/fix_shear_history.cpp

452 lines
13 KiB
C++

/* ----------------------------------------------------------------------
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<tagint>[nmypage];
dpage = new MyPage<double[3]>[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<int> (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<tagint> (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<int> (extra[nlocal][m]);
m++;
// allocate new chunks from ipage,dpage for incoming values
npartner[nlocal] = static_cast<int> (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<tagint> (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;
}