#include "fix_evaporate.h"
#include <mpi.h>
#include <cstring>
#include "atom.h"
#include "atom_vec.h"
#include "molecule.h"
#include "update.h"
#include "domain.h"
#include "region.h"
#include "comm.h"
#include "force.h"
#include "group.h"
#include "random_park.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
FixEvaporate::FixEvaporate(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg), idregion(NULL), list(NULL), mark(NULL), random(NULL)
{
if (narg < 7) error->all(FLERR,"Illegal fix evaporate command");
scalar_flag = 1;
global_freq = 1;
extscalar = 0;
nevery = force->inumeric(FLERR,arg[3]);
nflux = force->inumeric(FLERR,arg[4]);
iregion = domain->find_region(arg[5]);
int n = strlen(arg[5]) + 1;
idregion = new char[n];
strcpy(idregion,arg[5]);
int seed = force->inumeric(FLERR,arg[6]);
if (nevery <= 0 || nflux <= 0)
error->all(FLERR,"Illegal fix evaporate command");
if (iregion == -1)
error->all(FLERR,"Region ID for fix evaporate does not exist");
if (seed <= 0) error->all(FLERR,"Illegal fix evaporate command");
random = new RanPark(lmp,seed);
molflag = 0;
int iarg = 7;
while (iarg < narg) {
if (strcmp(arg[iarg],"molecule") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix evaporate command");
if (strcmp(arg[iarg+1],"no") == 0) molflag = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) molflag = 1;
else error->all(FLERR,"Illegal fix evaporate command");
iarg += 2;
} else error->all(FLERR,"Illegal fix evaporate command");
}
force_reneighbor = 1;
next_reneighbor = (update->ntimestep/nevery)*nevery + nevery;
ndeleted = 0;
nmax = 0;
list = NULL;
mark = NULL;
}
FixEvaporate::~FixEvaporate()
{
delete [] idregion;
delete random;
memory->destroy(list);
memory->destroy(mark);
}
int FixEvaporate::setmask()
{
int mask = 0;
mask |= PRE_EXCHANGE;
return mask;
}
void FixEvaporate::init()
{
iregion = domain->find_region(idregion);
if (iregion == -1)
error->all(FLERR,"Region ID for fix evaporate does not exist");
if (atom->firstgroup >= 0) {
int *mask = atom->mask;
int nlocal = atom->nlocal;
int firstgroupbit = group->bitmask[atom->firstgroup];
int flag = 0;
for (int i = 0; i < nlocal; i++)
if ((mask[i] & groupbit) && (mask[i] && firstgroupbit)) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall)
error->all(FLERR,"Cannot evaporate atoms in atom_modify first group");
}
if (molflag == 0 && atom->molecule_flag) {
tagint *molecule = atom->molecule;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int flag = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
if (molecule[i]) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall && comm->me == 0)
error->warning(FLERR,
"Fix evaporate may delete atom with non-zero molecule ID");
}
if (molflag && atom->molecule_flag == 0)
error->all(FLERR,
"Fix evaporate molecule requires atom attribute molecule");
}
void FixEvaporate::pre_exchange()
{
int i,j,m,iwhichglobal,iwhichlocal;
int ndel,ndeltopo[4];
if (update->ntimestep != next_reneighbor) return;
if (atom->nmax > nmax) {
memory->destroy(list);
memory->destroy(mark);
nmax = atom->nmax;
memory->create(list,nmax,"evaporate:list");
memory->create(mark,nmax,"evaporate:mark");
}
Region *region = domain->regions[iregion];
region->prematch();
double **x = atom->x;
int *mask = atom->mask;
tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int ncount = 0;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
if (region->match(x[i][0],x[i][1],x[i][2])) list[ncount++] = i;
int nall,nbefore;
MPI_Allreduce(&ncount,&nall,1,MPI_INT,MPI_SUM,world);
MPI_Scan(&ncount,&nbefore,1,MPI_INT,MPI_SUM,world);
nbefore -= ncount;
ndel = 0;
for (i = 0; i < nlocal; i++) mark[i] = 0;
if (molflag == 0) {
while (nall && ndel < nflux) {
iwhichglobal = static_cast<int> (nall*random->uniform());
if (iwhichglobal < nbefore) nbefore--;
else if (iwhichglobal < nbefore + ncount) {
iwhichlocal = iwhichglobal - nbefore;
mark[list[iwhichlocal]] = 1;
list[iwhichlocal] = list[ncount-1];
ncount--;
}
ndel++;
nall--;
}
} else {
int me,proc,iatom,ndelone,ndelall,index;
tagint imolecule;
tagint *molecule = atom->molecule;
int *molindex = atom->molindex;
int *molatom = atom->molatom;
int molecular = atom->molecular;
Molecule **onemols = atom->avec->onemols;
ndeltopo[0] = ndeltopo[1] = ndeltopo[2] = ndeltopo[3] = 0;
while (nall && ndel < nflux) {
iwhichglobal = static_cast<int> (nall*random->uniform());
if (iwhichglobal >= nbefore && iwhichglobal < nbefore + ncount) {
iwhichlocal = iwhichglobal - nbefore;
iatom = list[iwhichlocal];
imolecule = molecule[iatom];
me = comm->me;
} else me = -1;
MPI_Allreduce(&me,&proc,1,MPI_INT,MPI_MAX,world);
MPI_Bcast(&imolecule,1,MPI_LMP_TAGINT,proc,world);
ndelone = 0;
for (i = 0; i < nlocal; i++) {
if (imolecule && molecule[i] == imolecule) {
mark[i] = 1;
ndelone++;
if (molecular == 1) {
if (atom->avec->bonds_allow) {
if (force->newton_bond) ndeltopo[0] += atom->num_bond[i];
else {
for (j = 0; j < atom->num_bond[i]; j++) {
if (tag[i] < atom->bond_atom[i][j]) ndeltopo[0]++;
}
}
}
if (atom->avec->angles_allow) {
if (force->newton_bond) ndeltopo[1] += atom->num_angle[i];
else {
for (j = 0; j < atom->num_angle[i]; j++) {
m = atom->map(atom->angle_atom2[i][j]);
if (m >= 0 && m < nlocal) ndeltopo[1]++;
}
}
}
if (atom->avec->dihedrals_allow) {
if (force->newton_bond) ndeltopo[2] += atom->num_dihedral[i];
else {
for (j = 0; j < atom->num_dihedral[i]; j++) {
m = atom->map(atom->dihedral_atom2[i][j]);
if (m >= 0 && m < nlocal) ndeltopo[2]++;
}
}
}
if (atom->avec->impropers_allow) {
if (force->newton_bond) ndeltopo[3] += atom->num_improper[i];
else {
for (j = 0; j < atom->num_improper[i]; j++) {
m = atom->map(atom->improper_atom2[i][j]);
if (m >= 0 && m < nlocal) ndeltopo[3]++;
}
}
}
} else if (molecular == 2) {
if (molatom[i] == 0) {
index = molindex[i];
ndeltopo[0] += onemols[index]->nbonds;
ndeltopo[1] += onemols[index]->nangles;
ndeltopo[2] += onemols[index]->ndihedrals;
ndeltopo[3] += onemols[index]->nimpropers;
}
}
} else if (me == proc && i == iatom) {
mark[i] = 1;
ndelone++;
}
}
i = 0;
while (i < ncount) {
if (mark[list[i]]) {
list[i] = list[ncount-1];
ncount--;
} else i++;
}
MPI_Allreduce(&ndelone,&ndelall,1,MPI_INT,MPI_SUM,world);
ndel += ndelall;
MPI_Allreduce(&ncount,&nall,1,MPI_INT,MPI_SUM,world);
MPI_Scan(&ncount,&nbefore,1,MPI_INT,MPI_SUM,world);
nbefore -= ncount;
}
}
AtomVec *avec = atom->avec;
for (i = nlocal-1; i >= 0; i--) {
if (mark[i]) {
avec->copy(atom->nlocal-1,i,1);
atom->nlocal--;
}
}
atom->natoms -= ndel;
if (molflag) {
int all[4];
MPI_Allreduce(ndeltopo,all,4,MPI_INT,MPI_SUM,world);
atom->nbonds -= all[0];
atom->nangles -= all[1];
atom->ndihedrals -= all[2];
atom->nimpropers -= all[3];
}
if (ndel && atom->map_style) {
atom->nghost = 0;
atom->map_init();
atom->map_set();
}
ndeleted += ndel;
next_reneighbor = update->ntimestep + nevery;
}
double FixEvaporate::compute_scalar()
{
return 1.0*ndeleted;
}
double FixEvaporate::memory_usage()
{
double bytes = 2*nmax * sizeof(int);
return bytes;
}