git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@11827 f3b2605a-c512-4ea7-a41b-209d697bcdaa

This commit is contained in:
sjplimp 2014-04-18 15:15:25 +00:00
parent 13a3caa878
commit fa8155cb31
3 changed files with 197 additions and 59 deletions

View File

@ -31,7 +31,7 @@ compute the tesselation locally on each processor.
== Run tests ==
Run the includes test input file
./lmp_serial < lammps/examples/voronoi/in.vorotest | grep '^TEST_'
./lmp_serial < lammps/examples/voronoi/in.voronoi | grep '^TEST_'
The output should conclude with 'TEST_DONE' and every line should
report an error of 0%.

View File

@ -29,6 +29,7 @@
#include "comm.h"
#include "variable.h"
#include "input.h"
#include "force.h"
#include <vector>
@ -50,56 +51,62 @@ ComputeVoronoi::ComputeVoronoi(LAMMPS *lmp, int narg, char **arg) :
fthresh = ethresh = 0.0;
radstr = NULL;
onlyGroup = false;
occupation = false;
con_mono = NULL;
con_poly = NULL;
tags = occvec = sendocc = lroot = lnext = NULL;
int iarg = 3;
while ( iarg<narg ) {
if (strcmp(arg[iarg],"only_group") == 0) {
if (strcmp(arg[iarg], "occupation") == 0) {
occupation = true;
iarg++;
}
else if (strcmp(arg[iarg], "only_group") == 0) {
onlyGroup = true;
iarg++;
}
else if (strcmp(arg[iarg],"radius") == 0) {
if (iarg + 2 > narg || strstr(arg[iarg+1],"v_") != arg[iarg+1] )
error->all(FLERR,"Illegal compute voronoi/atom command");
else if (strcmp(arg[iarg], "radius") == 0) {
if (iarg + 2 > narg || strstr(arg[iarg+1],"v_") != arg[iarg+1] ) error->all(FLERR,"Missing atom style variable for radical voronoi tesselation radius.");
int n = strlen(&arg[iarg+1][2]) + 1;
radstr = new char[n];
strcpy(radstr,&arg[iarg+1][2]);
iarg += 2;
}
else if (strcmp(arg[iarg],"surface") == 0) {
if (iarg + 2 > narg)
error->all(FLERR,"Illegal compute voronoi/atom command");
else if (strcmp(arg[iarg], "surface") == 0) {
if (iarg + 2 > narg) error->all(FLERR,"Missing group name after keyword 'surface'.");
// group all is a special case where we just skip group testing
if(strcmp(arg[iarg+1], "all") == 0) {
surface = VOROSURF_ALL;
} else {
sgroup = group->find(arg[iarg+1]);
if (sgroup == -1)
error->all(FLERR,"Could not find compute/voronoi surface group ID");
if (sgroup == -1) error->all(FLERR,"Could not find compute/voronoi surface group ID");
sgroupbit = group->bitmask[sgroup];
surface = VOROSURF_GROUP;
}
size_peratom_cols = 3;
iarg += 2;
} else if (strcmp(arg[iarg], "edge_histo") == 0) {
if (iarg + 2 > narg)
error->all(FLERR,"Illegal compute voronoi/atom command");
maxedge = atoi(arg[iarg+1]);
if (iarg + 2 > narg) error->all(FLERR,"Missing maximum edge count after keyword 'edge_histo'.");
maxedge = force->inumeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg], "face_threshold") == 0) {
if (iarg + 2 > narg)
error->all(FLERR,"Illegal compute voronoi/atom command");
fthresh = atof(arg[iarg+1]);
if (iarg + 2 > narg) error->all(FLERR,"Missing minimum face area after keyword 'face_threshold'.");
fthresh = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg], "edge_threshold") == 0) {
if (iarg + 2 > narg)
error->all(FLERR,"Illegal compute voronoi/atom command");
ethresh = atof(arg[iarg+1]);
if (iarg + 2 > narg) error->all(FLERR,"Missing minimum edge length after keyword 'edge_threshold'.");
ethresh = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
}
else
error->all(FLERR,"Illegal compute voronoi/atom command");
}
if (occupation && ( surface!=VOROSURF_NONE || maxedge>0 ) )
error->all(FLERR,"Illegal compute voronoi/atom command (occupation and (surface or edges))");
nmax = rmax = 0;
edge = rfield = sendvector = NULL;
voro = NULL;
@ -122,17 +129,25 @@ ComputeVoronoi::~ComputeVoronoi()
memory->destroy(sendvector);
memory->destroy(voro);
delete[] radstr;
// voro++ container classes
delete con_mono;
delete con_poly;
// occupation analysis stuff
memory->destroy(lroot);
memory->destroy(lnext);
memory->destroy(occvec);
#ifdef NOTINPLACE
memory->destroy(sendocc);
#endif
memory->destroy(tags);
}
/* ---------------------------------------------------------------------- */
void ComputeVoronoi::init()
{
int count = 0;
for (int i = 0; i < modify->ncompute; i++)
if (strcmp(modify->compute[i]->style,"voronoi/atom") == 0) count++;
if (count > 1 && comm->me == 0)
error->warning(FLERR,"More than one compute voronoi/atom command");
}
/* ----------------------------------------------------------------------
@ -141,13 +156,9 @@ void ComputeVoronoi::init()
void ComputeVoronoi::compute_peratom()
{
int i;
const double e = 0.01;
invoked_peratom = update->ntimestep;
// grow per atom array if necessary
int nlocal = atom->nlocal;
if (nlocal > nmax) {
memory->destroy(voro);
@ -156,6 +167,48 @@ void ComputeVoronoi::compute_peratom()
array_atom = voro;
}
// decide between occupation or per-frame tesselation modes
if (occupation) {
// build cells only once
int i, j,
nall = nlocal + atom->nghost;
if (con_mono==NULL && con_poly==NULL) {
// generate the voronoi cell network for the initial structure
buildCells();
// save tags of atoms (i.e. of each voronoi cell)
memory->create(tags,nall,"voronoi/atom:tags");
for (i=0; i<nall; i++) tags[i] = atom->tag[i];
// linked list structure for cell occupation count on the atoms
oldnall= nall;
memory->create(lroot,nall,"voronoi/atom:lroot"); // point to first atom index in cell (or -1 for empty cell)
lnext = NULL;
lmax = 0;
// build the occupation buffer
oldnatoms = atom->natoms;
memory->create(occvec,oldnatoms,"voronoi/atom:occvec");
#ifdef NOTINPLACE
memory->create(sendocc,oldnatoms,"voronoi/atom:sendocc");
#endif
}
// get the occupation of each original voronoi cell
checkOccupation();
} else {
// build cells for each output
buildCells();
loopCells();
}
}
void ComputeVoronoi::buildCells()
{
int i, j;
const double e = 0.01;
int nlocal = atom->nlocal;
// in the onlyGroup mode we are not setting values for all atoms later in the voro loop
// initialize everything to zero here
if (onlyGroup) {
@ -182,7 +235,7 @@ void ComputeVoronoi::compute_peratom()
syz = domain->yz/my;
// cutghost is in lamda coordinates for triclinic boxes, use subxx_lamda
double *h = domain->h;
double *h = domain->h, cuttri[3];
sublo_bound[0] = h[0]*sublo_lamda[0] + h[5]*sublo_lamda[1] + h[4]*sublo_lamda[2] + boxlo[0];
sublo_bound[1] = h[1]*sublo_lamda[1] + h[3]*sublo_lamda[2] + boxlo[1];
sublo_bound[2] = h[2]*sublo_lamda[2] + boxlo[2];
@ -218,15 +271,14 @@ void ComputeVoronoi::compute_peratom()
// initialize voro++ container
// preallocates 8 atoms per cell
// voro++ allocates more memory if needed
voronoicell_neighbor c;
int *mask = atom->mask;
if(radstr) {
if (radstr) {
// check and fetch atom style variable data
int radvar = input->variable->find(radstr);
if (radvar < 0)
error->all(FLERR,"Variable name for voronoi radius does not exist");
error->all(FLERR,"Variable name for voronoi radius set does not exist");
if (!input->variable->atomstyle(radvar))
error->all(FLERR,"Variable for voronoi radius is not atom style");
error->all(FLERR,"Variable for voronoi radius is not atom style");
// prepare destination buffer for variable evaluation
if (nlocal > rmax) {
memory->destroy(rfield);
@ -240,7 +292,8 @@ void ComputeVoronoi::compute_peratom()
comm->forward_comm_compute(this);
// polydisperse voro++ container
container_poly con(sublo_bound[0]-cut_bound[0]-e,subhi_bound[0]+cut_bound[0]+e,
delete con_poly;
con_poly = new container_poly(sublo_bound[0]-cut_bound[0]-e,subhi_bound[0]+cut_bound[0]+e,
sublo_bound[1]-cut_bound[1]-e,subhi_bound[1]+cut_bound[1]+e,
sublo_bound[2]-cut_bound[2]-e,subhi_bound[2]+cut_bound[2]+e,
int(n[0]),int(n[1]),int(n[2]),false,false,false,8);
@ -248,17 +301,11 @@ void ComputeVoronoi::compute_peratom()
// pass coordinates for local and ghost atoms to voro++
for (i = 0; i < nall; i++)
if( !onlyGroup || (mask[i] & groupbit) )
con.put(i,x[i][0],x[i][1],x[i][2],rfield[i]);
// invoke voro++ and fetch results for owned atoms in group
c_loop_all cl(con);
if (cl.start()) do if (con.compute_cell(c,cl)) {
i = cl.pid();
processCell(c,i);
} while (cl.inc());
con_poly->put(i,x[i][0],x[i][1],x[i][2],rfield[i]);
} else {
// monodisperse voro++ container
container con(sublo_bound[0]-cut_bound[0]-e,subhi_bound[0]+cut_bound[0]+e,
delete con_mono;
con_mono = new container(sublo_bound[0]-cut_bound[0]-e,subhi_bound[0]+cut_bound[0]+e,
sublo_bound[1]-cut_bound[1]-e,subhi_bound[1]+cut_bound[1]+e,
sublo_bound[2]-cut_bound[2]-e,subhi_bound[2]+cut_bound[2]+e,
int(n[0]),int(n[1]),int(n[2]),false,false,false,8);
@ -266,11 +313,102 @@ void ComputeVoronoi::compute_peratom()
// pass coordinates for local and ghost atoms to voro++
for (i = 0; i < nall; i++)
if( !onlyGroup || (mask[i] & groupbit) )
con.put(i,x[i][0],x[i][1],x[i][2]);
con_mono->put(i,x[i][0],x[i][1],x[i][2]);
}
}
// invoke voro++ and fetch results for owned atoms in group
c_loop_all cl(con);
if (cl.start()) do if (con.compute_cell(c,cl)) {
void ComputeVoronoi::checkOccupation()
{
// clear occupation vector
memset(occvec, 0, oldnatoms*sizeof(*occvec));
int i, j, k,
nlocal = atom->nlocal,
nall = atom->nghost + nlocal;
double rx, ry, rz,
**x = atom->x;
// prepare destination buffer for variable evaluation
if (nall > lmax) {
memory->destroy(lnext);
lmax = atom->nmax;
memory->create(lnext,lmax,"voronoi/atom:lnext");
}
// clear lroot
for (i=0; i<oldnall; ++i) lroot[i] = -1;
// clear lnext
for (i=0; i<nall; ++i) lnext[i] = -1;
// loop over all local atoms and find out in which of the local first frame voronoi cells the are in
// (need to loop over ghosts, too, to get correct occupation numbers for the second column)
for (i=0; i<nall; ++i) {
// again: find_voronoi_cell() should be in the common base class. Why it is not, I don't know. Ask the voro++ author.
if (( radstr && con_poly->find_voronoi_cell(x[i][0], x[i][1], x[i][2], rx, ry, rz, k)) ||
( !radstr && con_mono->find_voronoi_cell(x[i][0], x[i][1], x[i][2], rx, ry, rz, k) )) {
// increase occupation count of this particular cell
// only for local atoms, as we do an MPI reduce sum later
if (i<nlocal) occvec[tags[k]-1]++;
// add this atom to the linked list of cell j
if (lroot[k]<0)
lroot[k]=i;
else {
j = lroot[k];
while (lnext[j]>=0) j=lnext[j];
lnext[j] = i;
}
}
}
// MPI sum occupation
#ifdef NOTINPLACE
memcpy(sendocc, occvec, oldnatoms*sizeof(*occvec));
MPI_Allreduce(sendocc, occvec, oldnatoms, MPI_INT, MPI_SUM, world);
#else
MPI_Allreduce(MPI_IN_PLACE, occvec, oldnatoms, MPI_INT, MPI_SUM, world);
#endif
// determine the total number of atoms in this atom's currently occupied cell
int c;
for (i=0; i<oldnall; i++) { // loop over lroot (old voronoi cells)
// count
c = 0;
j = lroot[i];
while (j>=0) {
c++;
j = lnext[j];
}
// set
j = lroot[i];
while (j>=0) {
voro[j][1] = c;
j = lnext[j];
}
}
// cherry pick currently owned atoms
for (i=0; i<nlocal; i++) {
// set the new atom count in the atom's first frame voronoi cell
voro[i][0] = occvec[atom->tag[i]-1];
}
}
void ComputeVoronoi::loopCells()
{
// invoke voro++ and fetch results for owned atoms in group
voronoicell_neighbor c;
int i;
if (radstr) {
c_loop_all cl(*con_poly);
if (cl.start()) do if (con_poly->compute_cell(c,cl)) {
i = cl.pid();
processCell(c,i);
} while (cl.inc());
} else {
c_loop_all cl(*con_mono);
if (cl.start()) do if (con_mono->compute_cell(c,cl)) {
i = cl.pid();
processCell(c,i);
} while (cl.inc());

View File

@ -38,6 +38,12 @@ class ComputeVoronoi : public Compute {
void unpack_comm(int, int, double *);
private:
voro::container *con_mono;
voro::container_poly *con_poly;
void buildCells();
void checkOccupation();
void loopCells();
void processCell(voro::voronoicell_neighbor&, int);
int nmax, rmax, maxedge, sgroupbit;
@ -46,7 +52,10 @@ class ComputeVoronoi : public Compute {
double **voro;
double *edge, *sendvector, *rfield;
enum { VOROSURF_NONE, VOROSURF_ALL, VOROSURF_GROUP } surface;
bool onlyGroup;
bool onlyGroup, occupation;
tagint *tags;
int *occvec, *sendocc, *lroot, *lnext, lmax, oldnatoms, oldnall;
};
}
@ -62,21 +71,12 @@ Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line.
E: Could not find compute/voronoi surface group ID
E: Compute voronoi/atom not allowed for triclinic boxes
Self-explanatory.
This is a current restriction of this command.
W: More than one compute voronoi/atom command
It is not efficient to use compute voronoi/atom more than once.
E: Variable name for voronoi radius does not exist
Self-explanatory.
E: Variable for voronoi radius is not atom style
The variable used for this command must be an atom-style variable.
See the variable command for details.
*/