forked from lijiext/lammps
git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@10366 f3b2605a-c512-4ea7-a41b-209d697bcdaa
This commit is contained in:
parent
dea3df948e
commit
87b941f250
|
@ -1,508 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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 "math.h"
|
|
||||||
#include "stdlib.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include "fix_deposit.h"
|
|
||||||
#include "atom.h"
|
|
||||||
#include "atom_vec.h"
|
|
||||||
#include "force.h"
|
|
||||||
#include "update.h"
|
|
||||||
#include "modify.h"
|
|
||||||
#include "fix.h"
|
|
||||||
#include "comm.h"
|
|
||||||
#include "domain.h"
|
|
||||||
#include "lattice.h"
|
|
||||||
#include "region.h"
|
|
||||||
#include "random_park.h"
|
|
||||||
#include "memory.h"
|
|
||||||
#include "error.h"
|
|
||||||
|
|
||||||
using namespace LAMMPS_NS;
|
|
||||||
using namespace FixConst;
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
FixDeposit::FixDeposit(LAMMPS *lmp, int narg, char **arg) :
|
|
||||||
Fix(lmp, narg, arg)
|
|
||||||
{
|
|
||||||
if (narg < 7) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
|
|
||||||
restart_global = 1;
|
|
||||||
time_depend = 1;
|
|
||||||
|
|
||||||
// required args
|
|
||||||
|
|
||||||
ninsert = force->inumeric(FLERR,arg[3]);
|
|
||||||
ntype = force->inumeric(FLERR,arg[4]);
|
|
||||||
nfreq = force->inumeric(FLERR,arg[5]);
|
|
||||||
seed = force->inumeric(FLERR,arg[6]);
|
|
||||||
|
|
||||||
if (seed <= 0) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
|
|
||||||
// set defaults
|
|
||||||
|
|
||||||
iregion = -1;
|
|
||||||
idregion = NULL;
|
|
||||||
idnext = 0;
|
|
||||||
globalflag = localflag = 0;
|
|
||||||
lo = hi = deltasq = 0.0;
|
|
||||||
nearsq = 0.0;
|
|
||||||
maxattempt = 10;
|
|
||||||
rateflag = 0;
|
|
||||||
vxlo = vxhi = vylo = vyhi = vzlo = vzhi = 0.0;
|
|
||||||
scaleflag = 1;
|
|
||||||
targetflag = 0;
|
|
||||||
|
|
||||||
// read options from end of input line
|
|
||||||
|
|
||||||
options(narg-7,&arg[7]);
|
|
||||||
|
|
||||||
// error checks on region and its extent being inside simulation box
|
|
||||||
|
|
||||||
if (iregion == -1) error->all(FLERR,"Must specify a region in fix deposit");
|
|
||||||
if (domain->regions[iregion]->bboxflag == 0)
|
|
||||||
error->all(FLERR,"Fix deposit region does not support a bounding box");
|
|
||||||
if (domain->regions[iregion]->dynamic_check())
|
|
||||||
error->all(FLERR,"Fix deposit region cannot be dynamic");
|
|
||||||
|
|
||||||
xlo = domain->regions[iregion]->extent_xlo;
|
|
||||||
xhi = domain->regions[iregion]->extent_xhi;
|
|
||||||
ylo = domain->regions[iregion]->extent_ylo;
|
|
||||||
yhi = domain->regions[iregion]->extent_yhi;
|
|
||||||
zlo = domain->regions[iregion]->extent_zlo;
|
|
||||||
zhi = domain->regions[iregion]->extent_zhi;
|
|
||||||
|
|
||||||
if (domain->triclinic == 0) {
|
|
||||||
if (xlo < domain->boxlo[0] || xhi > domain->boxhi[0] ||
|
|
||||||
ylo < domain->boxlo[1] || yhi > domain->boxhi[1] ||
|
|
||||||
zlo < domain->boxlo[2] || zhi > domain->boxhi[2])
|
|
||||||
error->all(FLERR,"Deposition region extends outside simulation box");
|
|
||||||
} else {
|
|
||||||
if (xlo < domain->boxlo_bound[0] || xhi > domain->boxhi_bound[0] ||
|
|
||||||
ylo < domain->boxlo_bound[1] || yhi > domain->boxhi_bound[1] ||
|
|
||||||
zlo < domain->boxlo_bound[2] || zhi > domain->boxhi_bound[2])
|
|
||||||
error->all(FLERR,"Deposition region extends outside simulation box");
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup scaling
|
|
||||||
|
|
||||||
double xscale,yscale,zscale;
|
|
||||||
if (scaleflag) {
|
|
||||||
xscale = domain->lattice->xlattice;
|
|
||||||
yscale = domain->lattice->ylattice;
|
|
||||||
zscale = domain->lattice->zlattice;
|
|
||||||
}
|
|
||||||
else xscale = yscale = zscale = 1.0;
|
|
||||||
|
|
||||||
// apply scaling to all input parameters with dist/vel units
|
|
||||||
|
|
||||||
if (domain->dimension == 2) {
|
|
||||||
lo *= yscale;
|
|
||||||
hi *= yscale;
|
|
||||||
rate *= yscale;
|
|
||||||
} else {
|
|
||||||
lo *= zscale;
|
|
||||||
hi *= zscale;
|
|
||||||
rate *= zscale;
|
|
||||||
}
|
|
||||||
deltasq *= xscale*xscale;
|
|
||||||
nearsq *= xscale*xscale;
|
|
||||||
vxlo *= xscale;
|
|
||||||
vxhi *= xscale;
|
|
||||||
vylo *= yscale;
|
|
||||||
vyhi *= yscale;
|
|
||||||
vzlo *= zscale;
|
|
||||||
vzhi *= zscale;
|
|
||||||
tx *= xscale;
|
|
||||||
ty *= yscale;
|
|
||||||
tz *= zscale;
|
|
||||||
|
|
||||||
// maxtag_all = current max tag for all atoms
|
|
||||||
|
|
||||||
if (idnext) {
|
|
||||||
int *tag = atom->tag;
|
|
||||||
int nlocal = atom->nlocal;
|
|
||||||
|
|
||||||
int maxtag = 0;
|
|
||||||
for (int i = 0; i < nlocal; i++) maxtag = MAX(maxtag,tag[i]);
|
|
||||||
MPI_Allreduce(&maxtag,&maxtag_all,1,MPI_INT,MPI_MAX,world);
|
|
||||||
}
|
|
||||||
|
|
||||||
// random number generator, same for all procs
|
|
||||||
|
|
||||||
random = new RanPark(lmp,seed);
|
|
||||||
|
|
||||||
// set up reneighboring
|
|
||||||
|
|
||||||
force_reneighbor = 1;
|
|
||||||
next_reneighbor = update->ntimestep + 1;
|
|
||||||
nfirst = next_reneighbor;
|
|
||||||
ninserted = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
FixDeposit::~FixDeposit()
|
|
||||||
{
|
|
||||||
delete random;
|
|
||||||
delete [] idregion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
int FixDeposit::setmask()
|
|
||||||
{
|
|
||||||
int mask = 0;
|
|
||||||
mask |= PRE_EXCHANGE;
|
|
||||||
return mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixDeposit::init()
|
|
||||||
{
|
|
||||||
// set index and check validity of region
|
|
||||||
|
|
||||||
iregion = domain->find_region(idregion);
|
|
||||||
if (iregion == -1)
|
|
||||||
error->all(FLERR,"Region ID for fix deposit does not exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
perform particle insertion
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixDeposit::pre_exchange()
|
|
||||||
{
|
|
||||||
int i,j;
|
|
||||||
int flag,flagall;
|
|
||||||
double coord[3],lamda[3],delx,dely,delz,rsq;
|
|
||||||
double *newcoord;
|
|
||||||
|
|
||||||
// just return if should not be called on this timestep
|
|
||||||
|
|
||||||
if (next_reneighbor != update->ntimestep) return;
|
|
||||||
|
|
||||||
// compute current offset = bottom of insertion volume
|
|
||||||
|
|
||||||
double offset = 0.0;
|
|
||||||
if (rateflag) offset = (update->ntimestep - nfirst) * update->dt * rate;
|
|
||||||
|
|
||||||
double *sublo,*subhi;
|
|
||||||
if (domain->triclinic == 0) {
|
|
||||||
sublo = domain->sublo;
|
|
||||||
subhi = domain->subhi;
|
|
||||||
} else {
|
|
||||||
sublo = domain->sublo_lamda;
|
|
||||||
subhi = domain->subhi_lamda;
|
|
||||||
}
|
|
||||||
|
|
||||||
// attempt an insertion until successful
|
|
||||||
|
|
||||||
int nfix = modify->nfix;
|
|
||||||
Fix **fix = modify->fix;
|
|
||||||
|
|
||||||
int success = 0;
|
|
||||||
int attempt = 0;
|
|
||||||
while (attempt < maxattempt) {
|
|
||||||
attempt++;
|
|
||||||
|
|
||||||
// choose random position for new atom within region
|
|
||||||
|
|
||||||
coord[0] = xlo + random->uniform() * (xhi-xlo);
|
|
||||||
coord[1] = ylo + random->uniform() * (yhi-ylo);
|
|
||||||
coord[2] = zlo + random->uniform() * (zhi-zlo);
|
|
||||||
while (domain->regions[iregion]->match(coord[0],coord[1],coord[2]) == 0) {
|
|
||||||
coord[0] = xlo + random->uniform() * (xhi-xlo);
|
|
||||||
coord[1] = ylo + random->uniform() * (yhi-ylo);
|
|
||||||
coord[2] = zlo + random->uniform() * (zhi-zlo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust vertical coord by offset
|
|
||||||
|
|
||||||
if (domain->dimension == 2) coord[1] += offset;
|
|
||||||
else coord[2] += offset;
|
|
||||||
|
|
||||||
// if global, reset vertical coord to be lo-hi above highest atom
|
|
||||||
// if local, reset vertical coord to be lo-hi above highest "nearby" atom
|
|
||||||
// local computation computes lateral distance between 2 particles w/ PBC
|
|
||||||
|
|
||||||
if (globalflag || localflag) {
|
|
||||||
int dim;
|
|
||||||
double max,maxall,delx,dely,delz,rsq;
|
|
||||||
|
|
||||||
if (domain->dimension == 2) {
|
|
||||||
dim = 1;
|
|
||||||
max = domain->boxlo[1];
|
|
||||||
} else {
|
|
||||||
dim = 2;
|
|
||||||
max = domain->boxlo[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
double **x = atom->x;
|
|
||||||
int nlocal = atom->nlocal;
|
|
||||||
for (i = 0; i < nlocal; i++) {
|
|
||||||
if (localflag) {
|
|
||||||
delx = coord[0] - x[i][0];
|
|
||||||
dely = coord[1] - x[i][1];
|
|
||||||
delz = 0.0;
|
|
||||||
domain->minimum_image(delx,dely,delz);
|
|
||||||
if (domain->dimension == 2) rsq = delx*delx;
|
|
||||||
else rsq = delx*delx + dely*dely;
|
|
||||||
if (rsq > deltasq) continue;
|
|
||||||
}
|
|
||||||
if (x[i][dim] > max) max = x[i][dim];
|
|
||||||
}
|
|
||||||
|
|
||||||
MPI_Allreduce(&max,&maxall,1,MPI_DOUBLE,MPI_MAX,world);
|
|
||||||
if (domain->dimension == 2)
|
|
||||||
coord[1] = maxall + lo + random->uniform()*(hi-lo);
|
|
||||||
else
|
|
||||||
coord[2] = maxall + lo + random->uniform()*(hi-lo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now have final coord
|
|
||||||
// if distance to any atom is less than near, try again
|
|
||||||
|
|
||||||
double **x = atom->x;
|
|
||||||
int nlocal = atom->nlocal;
|
|
||||||
|
|
||||||
flag = 0;
|
|
||||||
for (i = 0; i < nlocal; i++) {
|
|
||||||
delx = coord[0] - x[i][0];
|
|
||||||
dely = coord[1] - x[i][1];
|
|
||||||
delz = coord[2] - x[i][2];
|
|
||||||
domain->minimum_image(delx,dely,delz);
|
|
||||||
rsq = delx*delx + dely*dely + delz*delz;
|
|
||||||
if (rsq < nearsq) flag = 1;
|
|
||||||
}
|
|
||||||
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world);
|
|
||||||
if (flagall) continue;
|
|
||||||
|
|
||||||
// insertion will proceed
|
|
||||||
// choose random velocity for new atom
|
|
||||||
|
|
||||||
double vxtmp = vxlo + random->uniform() * (vxhi-vxlo);
|
|
||||||
double vytmp = vylo + random->uniform() * (vyhi-vylo);
|
|
||||||
double vztmp = vzlo + random->uniform() * (vzhi-vzlo);
|
|
||||||
|
|
||||||
// if we have a sputter target change velocity vector accordingly
|
|
||||||
if (targetflag) {
|
|
||||||
double vel = sqrt(vxtmp*vxtmp + vytmp*vytmp + vztmp*vztmp);
|
|
||||||
delx = tx - coord[0];
|
|
||||||
dely = ty - coord[1];
|
|
||||||
delz = tz - coord[2];
|
|
||||||
double rsq = delx*delx + dely*dely + delz*delz;
|
|
||||||
if (rsq > 0.0) {
|
|
||||||
double rinv = sqrt(1.0/rsq);
|
|
||||||
vxtmp = delx*rinv*vel;
|
|
||||||
vytmp = dely*rinv*vel;
|
|
||||||
vztmp = delz*rinv*vel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if new atom is in my sub-box or above it if I'm highest proc
|
|
||||||
// if so, add to my list via create_atom()
|
|
||||||
// initialize info about the atoms
|
|
||||||
// set group mask to "all" plus fix group
|
|
||||||
|
|
||||||
if (domain->triclinic) {
|
|
||||||
domain->x2lamda(coord,lamda);
|
|
||||||
newcoord = lamda;
|
|
||||||
} else newcoord = coord;
|
|
||||||
|
|
||||||
flag = 0;
|
|
||||||
if (newcoord[0] >= sublo[0] && newcoord[0] < subhi[0] &&
|
|
||||||
newcoord[1] >= sublo[1] && newcoord[1] < subhi[1] &&
|
|
||||||
newcoord[2] >= sublo[2] && newcoord[2] < subhi[2]) flag = 1;
|
|
||||||
else if (domain->dimension == 3 && newcoord[2] >= domain->boxhi[2] &&
|
|
||||||
comm->myloc[2] == comm->procgrid[2]-1 &&
|
|
||||||
newcoord[0] >= sublo[0] && newcoord[0] < subhi[0] &&
|
|
||||||
newcoord[1] >= sublo[1] && newcoord[1] < subhi[1]) flag = 1;
|
|
||||||
else if (domain->dimension == 2 && newcoord[1] >= domain->boxhi[1] &&
|
|
||||||
comm->myloc[1] == comm->procgrid[1]-1 &&
|
|
||||||
newcoord[0] >= sublo[0] && newcoord[0] < subhi[0]) flag = 1;
|
|
||||||
|
|
||||||
if (flag) {
|
|
||||||
atom->avec->create_atom(ntype,coord);
|
|
||||||
int m = atom->nlocal - 1;
|
|
||||||
atom->type[m] = ntype;
|
|
||||||
atom->mask[m] = 1 | groupbit;
|
|
||||||
atom->v[m][0] = vxtmp;
|
|
||||||
atom->v[m][1] = vytmp;
|
|
||||||
atom->v[m][2] = vztmp;
|
|
||||||
for (j = 0; j < nfix; j++)
|
|
||||||
if (fix[j]->create_attribute) fix[j]->set_arrays(m);
|
|
||||||
}
|
|
||||||
MPI_Allreduce(&flag,&success,1,MPI_INT,MPI_MAX,world);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// warn if not successful b/c too many attempts or no proc owned particle
|
|
||||||
|
|
||||||
if (!success && comm->me == 0)
|
|
||||||
error->warning(FLERR,"Particle deposition was unsuccessful",0);
|
|
||||||
|
|
||||||
// reset global natoms
|
|
||||||
// if idnext, set new atom ID to incremented maxtag_all
|
|
||||||
// else set new atom ID to value beyond all current atoms
|
|
||||||
// if global map exists, reset it now instead of waiting for comm
|
|
||||||
// since adding an atom messes up ghosts
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
atom->natoms += 1;
|
|
||||||
if (atom->tag_enable) {
|
|
||||||
if (idnext) {
|
|
||||||
maxtag_all++;
|
|
||||||
if (atom->nlocal && atom->tag[atom->nlocal-1] == 0)
|
|
||||||
atom->tag[atom->nlocal-1] = maxtag_all;
|
|
||||||
} else atom->tag_extend();
|
|
||||||
if (atom->map_style) {
|
|
||||||
atom->nghost = 0;
|
|
||||||
atom->map_init();
|
|
||||||
atom->map_set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// next timestep to insert
|
|
||||||
// next_reneighbor = 0 if done
|
|
||||||
|
|
||||||
if (success) ninserted++;
|
|
||||||
if (ninserted < ninsert) next_reneighbor += nfreq;
|
|
||||||
else next_reneighbor = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
parse optional parameters at end of input line
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixDeposit::options(int narg, char **arg)
|
|
||||||
{
|
|
||||||
if (narg < 0) error->all(FLERR,"Illegal fix indent command");
|
|
||||||
|
|
||||||
int iarg = 0;
|
|
||||||
while (iarg < narg) {
|
|
||||||
if (strcmp(arg[iarg],"region") == 0) {
|
|
||||||
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
iregion = domain->find_region(arg[iarg+1]);
|
|
||||||
if (iregion == -1)
|
|
||||||
error->all(FLERR,"Region ID for fix deposit does not exist");
|
|
||||||
int n = strlen(arg[iarg+1]) + 1;
|
|
||||||
idregion = new char[n];
|
|
||||||
strcpy(idregion,arg[iarg+1]);
|
|
||||||
iarg += 2;
|
|
||||||
} else if (strcmp(arg[iarg],"id") == 0) {
|
|
||||||
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
if (strcmp(arg[iarg+1],"max") == 0) idnext = 0;
|
|
||||||
else if (strcmp(arg[iarg+1],"next") == 0) idnext = 1;
|
|
||||||
else error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
iarg += 2;
|
|
||||||
} else if (strcmp(arg[iarg],"global") == 0) {
|
|
||||||
if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
globalflag = 1;
|
|
||||||
localflag = 0;
|
|
||||||
lo = force->numeric(FLERR,arg[iarg+1]);
|
|
||||||
hi = force->numeric(FLERR,arg[iarg+2]);
|
|
||||||
iarg += 3;
|
|
||||||
} else if (strcmp(arg[iarg],"local") == 0) {
|
|
||||||
if (iarg+4 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
localflag = 1;
|
|
||||||
globalflag = 0;
|
|
||||||
lo = force->numeric(FLERR,arg[iarg+1]);
|
|
||||||
hi = force->numeric(FLERR,arg[iarg+2]);
|
|
||||||
deltasq = force->numeric(FLERR,arg[iarg+3])*force->numeric(FLERR,arg[iarg+3]);
|
|
||||||
iarg += 4;
|
|
||||||
} else if (strcmp(arg[iarg],"near") == 0) {
|
|
||||||
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
nearsq = force->numeric(FLERR,arg[iarg+1])*force->numeric(FLERR,arg[iarg+1]);
|
|
||||||
iarg += 2;
|
|
||||||
} else if (strcmp(arg[iarg],"attempt") == 0) {
|
|
||||||
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
maxattempt = force->inumeric(FLERR,arg[iarg+1]);
|
|
||||||
iarg += 2;
|
|
||||||
} else if (strcmp(arg[iarg],"rate") == 0) {
|
|
||||||
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
rateflag = 1;
|
|
||||||
rate = force->numeric(FLERR,arg[iarg+1]);
|
|
||||||
iarg += 2;
|
|
||||||
} else if (strcmp(arg[iarg],"vx") == 0) {
|
|
||||||
if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
vxlo = force->numeric(FLERR,arg[iarg+1]);
|
|
||||||
vxhi = force->numeric(FLERR,arg[iarg+2]);
|
|
||||||
iarg += 3;
|
|
||||||
} else if (strcmp(arg[iarg],"vy") == 0) {
|
|
||||||
if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
vylo = force->numeric(FLERR,arg[iarg+1]);
|
|
||||||
vyhi = force->numeric(FLERR,arg[iarg+2]);
|
|
||||||
iarg += 3;
|
|
||||||
} else if (strcmp(arg[iarg],"vz") == 0) {
|
|
||||||
if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
vzlo = force->numeric(FLERR,arg[iarg+1]);
|
|
||||||
vzhi = force->numeric(FLERR,arg[iarg+2]);
|
|
||||||
iarg += 3;
|
|
||||||
} else if (strcmp(arg[iarg],"units") == 0) {
|
|
||||||
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0;
|
|
||||||
else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1;
|
|
||||||
else error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
iarg += 2;
|
|
||||||
} else if (strcmp(arg[iarg],"target") == 0) {
|
|
||||||
if (iarg+4 > narg) error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
tx = force->numeric(FLERR,arg[iarg+1]);
|
|
||||||
ty = force->numeric(FLERR,arg[iarg+2]);
|
|
||||||
tz = force->numeric(FLERR,arg[iarg+3]);
|
|
||||||
targetflag = 1;
|
|
||||||
iarg += 4;
|
|
||||||
} else error->all(FLERR,"Illegal fix deposit command");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
pack entire state of Fix into one write
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixDeposit::write_restart(FILE *fp)
|
|
||||||
{
|
|
||||||
int n = 0;
|
|
||||||
double list[4];
|
|
||||||
list[n++] = random->state();
|
|
||||||
list[n++] = ninserted;
|
|
||||||
list[n++] = nfirst;
|
|
||||||
list[n++] = next_reneighbor;
|
|
||||||
|
|
||||||
if (comm->me == 0) {
|
|
||||||
int size = n * sizeof(double);
|
|
||||||
fwrite(&size,sizeof(int),1,fp);
|
|
||||||
fwrite(list,sizeof(double),n,fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
use state info from restart file to restart the Fix
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixDeposit::restart(char *buf)
|
|
||||||
{
|
|
||||||
int n = 0;
|
|
||||||
double *list = (double *) buf;
|
|
||||||
|
|
||||||
seed = static_cast<int> (list[n++]);
|
|
||||||
ninserted = static_cast<int> (list[n++]);
|
|
||||||
nfirst = static_cast<int> (list[n++]);
|
|
||||||
next_reneighbor = static_cast<int> (list[n++]);
|
|
||||||
|
|
||||||
random->reset(seed);
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
/* -*- 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.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#ifdef FIX_CLASS
|
|
||||||
|
|
||||||
FixStyle(deposit,FixDeposit)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifndef LMP_FIX_DEPOSIT_H
|
|
||||||
#define LMP_FIX_DEPOSIT_H
|
|
||||||
|
|
||||||
#include "stdio.h"
|
|
||||||
#include "fix.h"
|
|
||||||
|
|
||||||
namespace LAMMPS_NS {
|
|
||||||
|
|
||||||
class FixDeposit : public Fix {
|
|
||||||
public:
|
|
||||||
FixDeposit(class LAMMPS *, int, char **);
|
|
||||||
~FixDeposit();
|
|
||||||
int setmask();
|
|
||||||
void init();
|
|
||||||
void pre_exchange();
|
|
||||||
void write_restart(FILE *);
|
|
||||||
void restart(char *);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int ninsert,ntype,nfreq,seed;
|
|
||||||
int iregion,globalflag,localflag,maxattempt,rateflag,scaleflag,targetflag;
|
|
||||||
char *idregion;
|
|
||||||
double lo,hi,deltasq,nearsq,rate;
|
|
||||||
double vxlo,vxhi,vylo,vyhi,vzlo,vzhi;
|
|
||||||
double xlo,xhi,ylo,yhi,zlo,zhi;
|
|
||||||
double tx,ty,tz;
|
|
||||||
int nfirst,ninserted;
|
|
||||||
int idnext,maxtag_all;
|
|
||||||
class RanPark *random;
|
|
||||||
|
|
||||||
void options(int, char **);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ERROR/WARNING messages:
|
|
||||||
|
|
||||||
E: Illegal ... command
|
|
||||||
|
|
||||||
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: Must specify a region in fix deposit
|
|
||||||
|
|
||||||
The region keyword must be specified with this fix.
|
|
||||||
|
|
||||||
E: Fix deposit region does not support a bounding box
|
|
||||||
|
|
||||||
Not all regions represent bounded volumes. You cannot use
|
|
||||||
such a region with the fix deposit command.
|
|
||||||
|
|
||||||
E: Fix deposit region cannot be dynamic
|
|
||||||
|
|
||||||
Only static regions can be used with fix deposit.
|
|
||||||
|
|
||||||
E: Deposition region extends outside simulation box
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Region ID for fix deposit does not exist
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
W: Particle deposition was unsuccessful
|
|
||||||
|
|
||||||
The fix deposit command was not able to insert as many atoms as
|
|
||||||
needed. The requested volume fraction may be too high, or other atoms
|
|
||||||
may be in the insertion region.
|
|
||||||
|
|
||||||
U: Use of fix deposit with undefined lattice
|
|
||||||
|
|
||||||
Must use lattice command with compute fix deposit command if units
|
|
||||||
option is set to lattice.
|
|
||||||
|
|
||||||
*/
|
|
|
@ -1,406 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
Contributing author: Christina Payne (Vanderbilt U)
|
|
||||||
Stan Moore (Sandia) for dipole terms
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#include "math.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include "stdlib.h"
|
|
||||||
#include "fix_efield.h"
|
|
||||||
#include "atom.h"
|
|
||||||
#include "update.h"
|
|
||||||
#include "domain.h"
|
|
||||||
#include "comm.h"
|
|
||||||
#include "modify.h"
|
|
||||||
#include "force.h"
|
|
||||||
#include "respa.h"
|
|
||||||
#include "input.h"
|
|
||||||
#include "variable.h"
|
|
||||||
#include "memory.h"
|
|
||||||
#include "error.h"
|
|
||||||
|
|
||||||
using namespace LAMMPS_NS;
|
|
||||||
using namespace FixConst;
|
|
||||||
|
|
||||||
enum{NONE,CONSTANT,EQUAL,ATOM};
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
FixEfield::FixEfield(LAMMPS *lmp, int narg, char **arg) :
|
|
||||||
Fix(lmp, narg, arg)
|
|
||||||
{
|
|
||||||
if (narg != 6) error->all(FLERR,"Illegal fix efield command");
|
|
||||||
|
|
||||||
vector_flag = 1;
|
|
||||||
scalar_flag = 1;
|
|
||||||
size_vector = 3;
|
|
||||||
global_freq = 1;
|
|
||||||
extvector = 1;
|
|
||||||
extscalar = 1;
|
|
||||||
|
|
||||||
qe2f = force->qe2f;
|
|
||||||
xstr = ystr = zstr = NULL;
|
|
||||||
|
|
||||||
if (strstr(arg[3],"v_") == arg[3]) {
|
|
||||||
int n = strlen(&arg[3][2]) + 1;
|
|
||||||
xstr = new char[n];
|
|
||||||
strcpy(xstr,&arg[3][2]);
|
|
||||||
} else {
|
|
||||||
ex = qe2f * force->numeric(FLERR,arg[3]);
|
|
||||||
xstyle = CONSTANT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strstr(arg[4],"v_") == arg[4]) {
|
|
||||||
int n = strlen(&arg[4][2]) + 1;
|
|
||||||
ystr = new char[n];
|
|
||||||
strcpy(ystr,&arg[4][2]);
|
|
||||||
} else {
|
|
||||||
ey = qe2f * force->numeric(FLERR,arg[4]);
|
|
||||||
ystyle = CONSTANT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strstr(arg[5],"v_") == arg[5]) {
|
|
||||||
int n = strlen(&arg[5][2]) + 1;
|
|
||||||
zstr = new char[n];
|
|
||||||
strcpy(zstr,&arg[5][2]);
|
|
||||||
} else {
|
|
||||||
ez = qe2f * force->numeric(FLERR,arg[5]);
|
|
||||||
zstyle = CONSTANT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// optional args
|
|
||||||
|
|
||||||
estr = NULL;
|
|
||||||
|
|
||||||
int iarg = 6;
|
|
||||||
while (iarg < narg) {
|
|
||||||
if (strcmp(arg[iarg],"energy") == 0) {
|
|
||||||
if (iarg+2 > narg) error->all(FLERR,"Illegal fix efield command");
|
|
||||||
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) {
|
|
||||||
int n = strlen(&arg[iarg+1][2]) + 1;
|
|
||||||
estr = new char[n];
|
|
||||||
strcpy(estr,&arg[iarg+1][2]);
|
|
||||||
} else error->all(FLERR,"Illegal fix efield command");
|
|
||||||
iarg += 2;
|
|
||||||
} else error->all(FLERR,"Illegal fix efield command");
|
|
||||||
}
|
|
||||||
|
|
||||||
force_flag = 0;
|
|
||||||
fsum[0] = fsum[1] = fsum[2] = fsum[3] = 0.0;
|
|
||||||
|
|
||||||
maxatom = 0;
|
|
||||||
efield = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
FixEfield::~FixEfield()
|
|
||||||
{
|
|
||||||
delete [] xstr;
|
|
||||||
delete [] ystr;
|
|
||||||
delete [] zstr;
|
|
||||||
delete [] estr;
|
|
||||||
memory->destroy(efield);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
int FixEfield::setmask()
|
|
||||||
{
|
|
||||||
int mask = 0;
|
|
||||||
mask |= THERMO_ENERGY;
|
|
||||||
mask |= POST_FORCE;
|
|
||||||
mask |= POST_FORCE_RESPA;
|
|
||||||
mask |= MIN_POST_FORCE;
|
|
||||||
return mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixEfield::init()
|
|
||||||
{
|
|
||||||
qflag = muflag = 0;
|
|
||||||
if (atom->q_flag) qflag = 1;
|
|
||||||
if (atom->mu_flag && atom->torque_flag) muflag = 1;
|
|
||||||
if (!qflag && !muflag)
|
|
||||||
error->all(FLERR,"Fix efield requires atom attribute q or mu");
|
|
||||||
|
|
||||||
// check variables
|
|
||||||
|
|
||||||
if (xstr) {
|
|
||||||
xvar = input->variable->find(xstr);
|
|
||||||
if (xvar < 0)
|
|
||||||
error->all(FLERR,"Variable name for fix efield does not exist");
|
|
||||||
if (input->variable->equalstyle(xvar)) xstyle = EQUAL;
|
|
||||||
else if (input->variable->atomstyle(xvar)) xstyle = ATOM;
|
|
||||||
else error->all(FLERR,"Variable for fix efield is invalid style");
|
|
||||||
}
|
|
||||||
if (ystr) {
|
|
||||||
yvar = input->variable->find(ystr);
|
|
||||||
if (yvar < 0)
|
|
||||||
error->all(FLERR,"Variable name for fix efield does not exist");
|
|
||||||
if (input->variable->equalstyle(yvar)) ystyle = EQUAL;
|
|
||||||
else if (input->variable->atomstyle(yvar)) ystyle = ATOM;
|
|
||||||
else error->all(FLERR,"Variable for fix efield is invalid style");
|
|
||||||
}
|
|
||||||
if (zstr) {
|
|
||||||
zvar = input->variable->find(zstr);
|
|
||||||
if (zvar < 0)
|
|
||||||
error->all(FLERR,"Variable name for fix efield does not exist");
|
|
||||||
if (input->variable->equalstyle(zvar)) zstyle = EQUAL;
|
|
||||||
else if (input->variable->atomstyle(zvar)) zstyle = ATOM;
|
|
||||||
else error->all(FLERR,"Variable for fix efield is invalid style");
|
|
||||||
}
|
|
||||||
if (estr) {
|
|
||||||
evar = input->variable->find(estr);
|
|
||||||
if (evar < 0)
|
|
||||||
error->all(FLERR,"Variable name for fix efield does not exist");
|
|
||||||
if (input->variable->atomstyle(evar)) estyle = ATOM;
|
|
||||||
else error->all(FLERR,"Variable for fix efield is invalid style");
|
|
||||||
} else estyle = NONE;
|
|
||||||
|
|
||||||
if (xstyle == ATOM || ystyle == ATOM || zstyle == ATOM)
|
|
||||||
varflag = ATOM;
|
|
||||||
else if (xstyle == EQUAL || ystyle == EQUAL || zstyle == EQUAL)
|
|
||||||
varflag = EQUAL;
|
|
||||||
else varflag = CONSTANT;
|
|
||||||
|
|
||||||
if (muflag && varflag == ATOM)
|
|
||||||
error->all(FLERR,"Fix efield with dipoles cannot use atom-style variables");
|
|
||||||
|
|
||||||
if (muflag && update->whichflag == 2 && comm->me == 0)
|
|
||||||
error->warning(FLERR,
|
|
||||||
"The minimizer does not re-orient dipoles "
|
|
||||||
"when using fix efield");
|
|
||||||
|
|
||||||
if (varflag == CONSTANT && estyle != NONE)
|
|
||||||
error->all(FLERR,"Cannot use variable energy with "
|
|
||||||
"constant efield in fix efield");
|
|
||||||
if ((varflag == EQUAL || varflag == ATOM) &&
|
|
||||||
update->whichflag == 2 && estyle == NONE)
|
|
||||||
error->all(FLERR,"Must use variable energy with fix efield");
|
|
||||||
|
|
||||||
if (strstr(update->integrate_style,"respa"))
|
|
||||||
nlevels_respa = ((Respa *) update->integrate)->nlevels;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixEfield::setup(int vflag)
|
|
||||||
{
|
|
||||||
if (strstr(update->integrate_style,"verlet"))
|
|
||||||
post_force(vflag);
|
|
||||||
else {
|
|
||||||
((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1);
|
|
||||||
post_force_respa(vflag,nlevels_respa-1,0);
|
|
||||||
((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixEfield::min_setup(int vflag)
|
|
||||||
{
|
|
||||||
post_force(vflag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
apply F = qE
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixEfield::post_force(int vflag)
|
|
||||||
{
|
|
||||||
double **f = atom->f;
|
|
||||||
double *q = atom->q;
|
|
||||||
int *mask = atom->mask;
|
|
||||||
tagint *image = atom->image;
|
|
||||||
int nlocal = atom->nlocal;
|
|
||||||
|
|
||||||
// reallocate efield array if necessary
|
|
||||||
|
|
||||||
if (varflag == ATOM && nlocal > maxatom) {
|
|
||||||
maxatom = atom->nmax;
|
|
||||||
memory->destroy(efield);
|
|
||||||
memory->create(efield,maxatom,4,"efield:efield");
|
|
||||||
}
|
|
||||||
|
|
||||||
// fsum[0] = "potential energy" for added force
|
|
||||||
// fsum[123] = extra force added to atoms
|
|
||||||
|
|
||||||
fsum[0] = fsum[1] = fsum[2] = fsum[3] = 0.0;
|
|
||||||
force_flag = 0;
|
|
||||||
|
|
||||||
double **x = atom->x;
|
|
||||||
double fx,fy,fz;
|
|
||||||
|
|
||||||
// constant efield
|
|
||||||
|
|
||||||
if (varflag == CONSTANT) {
|
|
||||||
double unwrap[3];
|
|
||||||
|
|
||||||
// charge interactions
|
|
||||||
// force = qE, potential energy = F dot x in unwrapped coords
|
|
||||||
|
|
||||||
if (qflag) {
|
|
||||||
for (int i = 0; i < nlocal; i++)
|
|
||||||
if (mask[i] & groupbit) {
|
|
||||||
fx = q[i]*ex;
|
|
||||||
fy = q[i]*ey;
|
|
||||||
fz = q[i]*ez;
|
|
||||||
f[i][0] += fx;
|
|
||||||
f[i][1] += fy;
|
|
||||||
f[i][2] += fz;
|
|
||||||
|
|
||||||
domain->unmap(x[i],image[i],unwrap);
|
|
||||||
fsum[0] -= fx*unwrap[0]+fy*unwrap[1]+fz*unwrap[2];
|
|
||||||
fsum[1] += fx;
|
|
||||||
fsum[2] += fy;
|
|
||||||
fsum[3] += fz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dipole interactions
|
|
||||||
// no force, torque = mu cross E, potential energy = -mu dot E
|
|
||||||
|
|
||||||
if (muflag) {
|
|
||||||
double **mu = atom->mu;
|
|
||||||
double **t = atom->torque;
|
|
||||||
double tx,ty,tz;
|
|
||||||
for (int i = 0; i < nlocal; i++)
|
|
||||||
if (mask[i] & groupbit) {
|
|
||||||
tx = ez*mu[i][1] - ey*mu[i][2];
|
|
||||||
ty = ex*mu[i][2] - ez*mu[i][0];
|
|
||||||
tz = ey*mu[i][0] - ex*mu[i][1];
|
|
||||||
t[i][0] += tx;
|
|
||||||
t[i][1] += ty;
|
|
||||||
t[i][2] += tz;
|
|
||||||
fsum[0] -= mu[i][0]*ex + mu[i][1]*ey + mu[i][2]*ez;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// variable efield, wrap with clear/add
|
|
||||||
// potential energy = evar if defined, else 0.0
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
modify->clearstep_compute();
|
|
||||||
|
|
||||||
if (xstyle == EQUAL) ex = qe2f * input->variable->compute_equal(xvar);
|
|
||||||
else if (xstyle == ATOM && efield)
|
|
||||||
input->variable->compute_atom(xvar,igroup,&efield[0][0],3,0);
|
|
||||||
if (ystyle == EQUAL) ey = qe2f * input->variable->compute_equal(yvar);
|
|
||||||
else if (ystyle == ATOM && efield)
|
|
||||||
input->variable->compute_atom(yvar,igroup,&efield[0][1],3,0);
|
|
||||||
if (zstyle == EQUAL) ez = qe2f * input->variable->compute_equal(zvar);
|
|
||||||
else if (zstyle == ATOM && efield)
|
|
||||||
input->variable->compute_atom(zvar,igroup,&efield[0][2],3,0);
|
|
||||||
if (estyle == ATOM && efield)
|
|
||||||
input->variable->compute_atom(evar,igroup,&efield[0][3],4,0);
|
|
||||||
|
|
||||||
modify->addstep_compute(update->ntimestep + 1);
|
|
||||||
|
|
||||||
// charge interactions
|
|
||||||
// force = qE
|
|
||||||
|
|
||||||
if (qflag) {
|
|
||||||
for (int i = 0; i < nlocal; i++)
|
|
||||||
if (mask[i] & groupbit) {
|
|
||||||
if (xstyle == ATOM) fx = qe2f * q[i]*efield[i][0];
|
|
||||||
else fx = q[i]*ex;
|
|
||||||
f[i][0] += fx;
|
|
||||||
fsum[1] += fx;
|
|
||||||
if (ystyle == ATOM) fy = qe2f * q[i]*efield[i][1];
|
|
||||||
else fy = q[i]*ey;
|
|
||||||
f[i][1] += fy;
|
|
||||||
fsum[2] += fy;
|
|
||||||
if (zstyle == ATOM) fz = qe2f * q[i]*efield[i][2];
|
|
||||||
else fz = q[i]*ez;
|
|
||||||
f[i][2] += fz;
|
|
||||||
fsum[3] += fz;
|
|
||||||
if (estyle == ATOM) fsum[0] += efield[0][3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dipole interactions
|
|
||||||
// no force, torque = mu cross E
|
|
||||||
|
|
||||||
if (muflag) {
|
|
||||||
double **mu = atom->mu;
|
|
||||||
double **t = atom->torque;
|
|
||||||
double tx,ty,tz;
|
|
||||||
for (int i = 0; i < nlocal; i++)
|
|
||||||
if (mask[i] & groupbit) {
|
|
||||||
tx = ez*mu[i][1] - ey*mu[i][2];
|
|
||||||
ty = ex*mu[i][2] - ez*mu[i][0];
|
|
||||||
tz = ey*mu[i][0] - ex*mu[i][1];
|
|
||||||
t[i][0] += tx;
|
|
||||||
t[i][1] += ty;
|
|
||||||
t[i][2] += tz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixEfield::post_force_respa(int vflag, int ilevel, int iloop)
|
|
||||||
{
|
|
||||||
if (ilevel == nlevels_respa-1) post_force(vflag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixEfield::min_post_force(int vflag)
|
|
||||||
{
|
|
||||||
post_force(vflag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
memory usage of local atom-based array
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
double FixEfield::memory_usage()
|
|
||||||
{
|
|
||||||
double bytes = 0.0;
|
|
||||||
if (varflag == ATOM) bytes = atom->nmax*4 * sizeof(double);
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
return energy added by fix
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
double FixEfield::compute_scalar(void)
|
|
||||||
{
|
|
||||||
if (force_flag == 0) {
|
|
||||||
MPI_Allreduce(fsum,fsum_all,4,MPI_DOUBLE,MPI_SUM,world);
|
|
||||||
force_flag = 1;
|
|
||||||
}
|
|
||||||
return fsum_all[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
return total extra force due to fix
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
double FixEfield::compute_vector(int n)
|
|
||||||
{
|
|
||||||
if (force_flag == 0) {
|
|
||||||
MPI_Allreduce(fsum,fsum_all,4,MPI_DOUBLE,MPI_SUM,world);
|
|
||||||
force_flag = 1;
|
|
||||||
}
|
|
||||||
return fsum_all[n+1];
|
|
||||||
}
|
|
101
src/fix_efield.h
101
src/fix_efield.h
|
@ -1,101 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#ifdef FIX_CLASS
|
|
||||||
|
|
||||||
FixStyle(efield,FixEfield)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifndef LMP_FIX_EFIELD_H
|
|
||||||
#define LMP_FIX_EFIELD_H
|
|
||||||
|
|
||||||
#include "fix.h"
|
|
||||||
|
|
||||||
namespace LAMMPS_NS {
|
|
||||||
|
|
||||||
class FixEfield : public Fix {
|
|
||||||
public:
|
|
||||||
FixEfield(class LAMMPS *, int, char **);
|
|
||||||
~FixEfield();
|
|
||||||
int setmask();
|
|
||||||
void init();
|
|
||||||
void setup(int);
|
|
||||||
void min_setup(int);
|
|
||||||
void post_force(int);
|
|
||||||
void post_force_respa(int, int, int);
|
|
||||||
void min_post_force(int);
|
|
||||||
double memory_usage();
|
|
||||||
double compute_scalar();
|
|
||||||
double compute_vector(int);
|
|
||||||
|
|
||||||
private:
|
|
||||||
double ex,ey,ez;
|
|
||||||
int varflag;
|
|
||||||
char *xstr,*ystr,*zstr,*estr;
|
|
||||||
int xvar,yvar,zvar,evar,xstyle,ystyle,zstyle,estyle;
|
|
||||||
int nlevels_respa;
|
|
||||||
double qe2f;
|
|
||||||
double fdotx;
|
|
||||||
int qflag,muflag;
|
|
||||||
|
|
||||||
int maxatom;
|
|
||||||
double **efield;
|
|
||||||
|
|
||||||
int force_flag;
|
|
||||||
double fsum[4],fsum_all[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ERROR/WARNING messages:
|
|
||||||
|
|
||||||
E: Illegal ... command
|
|
||||||
|
|
||||||
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: Fix efield requires atom attribute q or mu
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Variable name for fix efield does not exist
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Variable for fix efield is invalid style
|
|
||||||
|
|
||||||
Only equal-style or atom-style variables can be used.
|
|
||||||
|
|
||||||
E: Fix efield with dipoles cannot use atom-style variables
|
|
||||||
|
|
||||||
This feature is not yet supported.
|
|
||||||
|
|
||||||
W: The minimizer does not re-orient dipoles when using fix efield
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Cannot use variable energy with constant efield in fix efield
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Must use variable energy with fix efield
|
|
||||||
|
|
||||||
One or more variables are defined for fix efield, which require
|
|
||||||
variable energy when using the minimizer.
|
|
||||||
|
|
||||||
*/
|
|
|
@ -1,386 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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 "math.h"
|
|
||||||
#include "stdlib.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include "fix_evaporate.h"
|
|
||||||
#include "atom.h"
|
|
||||||
#include "atom_vec.h"
|
|
||||||
#include "update.h"
|
|
||||||
#include "domain.h"
|
|
||||||
#include "region.h"
|
|
||||||
#include "comm.h"
|
|
||||||
#include "force.h"
|
|
||||||
#include "group.h"
|
|
||||||
#include "random_park.h"
|
|
||||||
#include "random_mars.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)
|
|
||||||
{
|
|
||||||
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 number generator, same for all procs
|
|
||||||
|
|
||||||
random = new RanPark(lmp,seed);
|
|
||||||
|
|
||||||
// optional args
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
// set up reneighboring
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
// set index and check validity of region
|
|
||||||
|
|
||||||
iregion = domain->find_region(idregion);
|
|
||||||
if (iregion == -1)
|
|
||||||
error->all(FLERR,"Region ID for fix evaporate does not exist");
|
|
||||||
|
|
||||||
// check that no deletable atoms are in atom->firstgroup
|
|
||||||
// deleting such an atom would not leave firstgroup atoms first
|
|
||||||
|
|
||||||
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 not set, warn if any deletable atom has a mol ID
|
|
||||||
|
|
||||||
if (molflag == 0 && atom->molecule_flag) {
|
|
||||||
int *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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
perform particle deletion
|
|
||||||
done before exchange, borders, reneighbor
|
|
||||||
so that ghost atoms and neighbor lists will be correct
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixEvaporate::pre_exchange()
|
|
||||||
{
|
|
||||||
int i,j,m,iwhichglobal,iwhichlocal;
|
|
||||||
int ndel,ndeltopo[4];
|
|
||||||
|
|
||||||
if (update->ntimestep != next_reneighbor) return;
|
|
||||||
|
|
||||||
// grow list and mark arrays if necessary
|
|
||||||
|
|
||||||
if (atom->nlocal > nmax) {
|
|
||||||
memory->destroy(list);
|
|
||||||
memory->destroy(mark);
|
|
||||||
nmax = atom->nmax;
|
|
||||||
memory->create(list,nmax,"evaporate:list");
|
|
||||||
memory->create(mark,nmax,"evaporate:mark");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ncount = # of deletable atoms in region that I own
|
|
||||||
// nall = # on all procs
|
|
||||||
// nbefore = # on procs before me
|
|
||||||
// list[ncount] = list of local indices of atoms I can delete
|
|
||||||
|
|
||||||
double **x = atom->x;
|
|
||||||
int *mask = atom->mask;
|
|
||||||
int *tag = atom->tag;
|
|
||||||
int nlocal = atom->nlocal;
|
|
||||||
|
|
||||||
int ncount = 0;
|
|
||||||
for (i = 0; i < nlocal; i++)
|
|
||||||
if (mask[i] & groupbit)
|
|
||||||
if (domain->regions[iregion]->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 = total # of atom deletions, in or out of region
|
|
||||||
// ndeltopo[1,2,3,4] = ditto for bonds, angles, dihedrals, impropers
|
|
||||||
// mark[] = 1 if deleted
|
|
||||||
|
|
||||||
ndel = 0;
|
|
||||||
for (i = 0; i < nlocal; i++) mark[i] = 0;
|
|
||||||
|
|
||||||
// atomic deletions
|
|
||||||
// choose atoms randomly across all procs and mark them for deletion
|
|
||||||
// shrink eligible list as my atoms get marked
|
|
||||||
// keep ndel,ncount,nall,nbefore current after each atom deletion
|
|
||||||
|
|
||||||
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--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// molecule deletions
|
|
||||||
// choose one atom in one molecule randomly across all procs
|
|
||||||
// bcast mol ID and delete all atoms in that molecule on any proc
|
|
||||||
// update deletion count by total # of atoms in molecule
|
|
||||||
// shrink list of eligible candidates as any of my atoms get marked
|
|
||||||
// keep ndel,ndeltopo,ncount,nall,nbefore current after each mol deletion
|
|
||||||
|
|
||||||
} else {
|
|
||||||
int me,proc,iatom,imolecule,ndelone,ndelall;
|
|
||||||
int *molecule = atom->molecule;
|
|
||||||
|
|
||||||
ndeltopo[0] = ndeltopo[1] = ndeltopo[2] = ndeltopo[3] = 0;
|
|
||||||
|
|
||||||
while (nall && ndel < nflux) {
|
|
||||||
|
|
||||||
// pick an iatom,imolecule on proc me to delete
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// bcast mol ID to delete all atoms from
|
|
||||||
// if mol ID > 0, delete any atom in molecule and decrement counters
|
|
||||||
// if mol ID == 0, delete single iatom
|
|
||||||
// be careful to delete correct # of bond,angle,etc for newton on or off
|
|
||||||
|
|
||||||
MPI_Allreduce(&me,&proc,1,MPI_INT,MPI_MAX,world);
|
|
||||||
MPI_Bcast(&imolecule,1,MPI_INT,proc,world);
|
|
||||||
ndelone = 0;
|
|
||||||
for (i = 0; i < nlocal; i++) {
|
|
||||||
if (imolecule && molecule[i] == imolecule) {
|
|
||||||
mark[i] = 1;
|
|
||||||
ndelone++;
|
|
||||||
|
|
||||||
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 (me == proc && i == iatom) {
|
|
||||||
mark[i] = 1;
|
|
||||||
ndelone++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove any atoms marked for deletion from my eligible list
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (i < ncount) {
|
|
||||||
if (mark[list[i]]) {
|
|
||||||
list[i] = list[ncount-1];
|
|
||||||
ncount--;
|
|
||||||
} else i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update ndel,ncount,nall,nbefore
|
|
||||||
// ndelall is total atoms deleted on this iteration
|
|
||||||
// ncount is already correct, so resum to get nall and nbefore
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete my marked atoms
|
|
||||||
// loop in reverse order to avoid copying marked atoms
|
|
||||||
|
|
||||||
AtomVec *avec = atom->avec;
|
|
||||||
|
|
||||||
for (i = nlocal-1; i >= 0; i--) {
|
|
||||||
if (mark[i]) {
|
|
||||||
avec->copy(atom->nlocal-1,i,1);
|
|
||||||
atom->nlocal--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset global natoms and bonds, angles, etc
|
|
||||||
// if global map exists, reset it now instead of waiting for comm
|
|
||||||
// since deleting atoms messes up ghosts
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// statistics
|
|
||||||
|
|
||||||
ndeleted += ndel;
|
|
||||||
next_reneighbor = update->ntimestep + nevery;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
return number of deleted particles
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
double FixEvaporate::compute_scalar()
|
|
||||||
{
|
|
||||||
return 1.0*ndeleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
memory usage of local atom-based arrays
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
double FixEvaporate::memory_usage()
|
|
||||||
{
|
|
||||||
double bytes = 2*nmax * sizeof(int);
|
|
||||||
return bytes;
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#ifdef FIX_CLASS
|
|
||||||
|
|
||||||
FixStyle(evaporate,FixEvaporate)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifndef LMP_FIX_EVAPORATE_H
|
|
||||||
#define LMP_FIX_EVAPORATE_H
|
|
||||||
|
|
||||||
#include "fix.h"
|
|
||||||
|
|
||||||
namespace LAMMPS_NS {
|
|
||||||
|
|
||||||
class FixEvaporate : public Fix {
|
|
||||||
public:
|
|
||||||
FixEvaporate(class LAMMPS *, int, char **);
|
|
||||||
~FixEvaporate();
|
|
||||||
int setmask();
|
|
||||||
void init();
|
|
||||||
void pre_exchange();
|
|
||||||
double compute_scalar();
|
|
||||||
double memory_usage();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int nevery,nflux,iregion;
|
|
||||||
int molflag;
|
|
||||||
int ndeleted;
|
|
||||||
char *idregion;
|
|
||||||
|
|
||||||
int nmax;
|
|
||||||
int *list,*mark;
|
|
||||||
|
|
||||||
class RanPark *random;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ERROR/WARNING messages:
|
|
||||||
|
|
||||||
E: Illegal ... command
|
|
||||||
|
|
||||||
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: Region ID for fix evaporate does not exist
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Cannot evaporate atoms in atom_modify first group
|
|
||||||
|
|
||||||
This is a restriction due to the way atoms are organized in
|
|
||||||
a list to enable the atom_modify first command.
|
|
||||||
|
|
||||||
W: Fix evaporate may delete atom with non-zero molecule ID
|
|
||||||
|
|
||||||
This is probably an error, since you should not delete only one atom
|
|
||||||
of a molecule.
|
|
||||||
|
|
||||||
E: Fix evaporate molecule requires atom attribute molecule
|
|
||||||
|
|
||||||
The atom style being used does not define a molecule ID.
|
|
||||||
|
|
||||||
*/
|
|
|
@ -1,330 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
Contributing author: Craig Tenney (UND) added support
|
|
||||||
for swapping atoms of different masses
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#include "math.h"
|
|
||||||
#include "mpi.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include "stdlib.h"
|
|
||||||
#include "fix_thermal_conductivity.h"
|
|
||||||
#include "atom.h"
|
|
||||||
#include "force.h"
|
|
||||||
#include "domain.h"
|
|
||||||
#include "modify.h"
|
|
||||||
#include "error.h"
|
|
||||||
|
|
||||||
using namespace LAMMPS_NS;
|
|
||||||
using namespace FixConst;
|
|
||||||
|
|
||||||
#define BIG 1.0e10
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
FixThermalConductivity::FixThermalConductivity(LAMMPS *lmp,
|
|
||||||
int narg, char **arg) :
|
|
||||||
Fix(lmp, narg, arg)
|
|
||||||
{
|
|
||||||
if (narg < 6) error->all(FLERR,"Illegal fix thermal/conductivity command");
|
|
||||||
|
|
||||||
MPI_Comm_rank(world,&me);
|
|
||||||
|
|
||||||
nevery = force->inumeric(FLERR,arg[3]);
|
|
||||||
if (nevery <= 0) error->all(FLERR,"Illegal fix thermal/conductivity command");
|
|
||||||
|
|
||||||
scalar_flag = 1;
|
|
||||||
global_freq = nevery;
|
|
||||||
extscalar = 0;
|
|
||||||
|
|
||||||
if (strcmp(arg[4],"x") == 0) edim = 0;
|
|
||||||
else if (strcmp(arg[4],"y") == 0) edim = 1;
|
|
||||||
else if (strcmp(arg[4],"z") == 0) edim = 2;
|
|
||||||
else error->all(FLERR,"Illegal fix thermal/conductivity command");
|
|
||||||
|
|
||||||
nbin = force->inumeric(FLERR,arg[5]);
|
|
||||||
if (nbin % 2 || nbin <= 2)
|
|
||||||
error->all(FLERR,"Illegal fix thermal/conductivity command");
|
|
||||||
|
|
||||||
// optional keywords
|
|
||||||
|
|
||||||
nswap = 1;
|
|
||||||
|
|
||||||
int iarg = 6;
|
|
||||||
while (iarg < narg) {
|
|
||||||
if (strcmp(arg[iarg],"swap") == 0) {
|
|
||||||
if (iarg+2 > narg)
|
|
||||||
error->all(FLERR,"Illegal fix thermal/conductivity command");
|
|
||||||
nswap = force->inumeric(FLERR,arg[iarg+1]);
|
|
||||||
if (nswap <= 0)
|
|
||||||
error->all(FLERR,
|
|
||||||
"Fix thermal/conductivity swap value must be positive");
|
|
||||||
iarg += 2;
|
|
||||||
} else error->all(FLERR,"Illegal fix thermal/conductivity command");
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize array sizes to nswap+1 so have space to shift values down
|
|
||||||
|
|
||||||
index_lo = new int[nswap+1];
|
|
||||||
index_hi = new int[nswap+1];
|
|
||||||
ke_lo = new double[nswap+1];
|
|
||||||
ke_hi = new double[nswap+1];
|
|
||||||
|
|
||||||
e_exchange = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
FixThermalConductivity::~FixThermalConductivity()
|
|
||||||
{
|
|
||||||
delete [] index_lo;
|
|
||||||
delete [] index_hi;
|
|
||||||
delete [] ke_lo;
|
|
||||||
delete [] ke_hi;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
int FixThermalConductivity::setmask()
|
|
||||||
{
|
|
||||||
int mask = 0;
|
|
||||||
mask |= END_OF_STEP;
|
|
||||||
return mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixThermalConductivity::init()
|
|
||||||
{
|
|
||||||
// warn if any fix ave/spatial comes after this fix
|
|
||||||
// can cause glitch in averaging since ave will happen after swap
|
|
||||||
|
|
||||||
int foundme = 0;
|
|
||||||
for (int i = 0; i < modify->nfix; i++) {
|
|
||||||
if (modify->fix[i] == this) foundme = 1;
|
|
||||||
if (foundme && strcmp(modify->fix[i]->style,"ave/spatial") == 0 && me == 0)
|
|
||||||
error->warning(FLERR,
|
|
||||||
"Fix thermal/conductivity comes before fix ave/spatial");
|
|
||||||
}
|
|
||||||
|
|
||||||
// set bounds of 2 slabs in edim
|
|
||||||
// only necessary for static box, else re-computed in end_of_step()
|
|
||||||
// lo bin is always bottom bin
|
|
||||||
// hi bin is just above half height
|
|
||||||
|
|
||||||
if (domain->box_change == 0) {
|
|
||||||
prd = domain->prd[edim];
|
|
||||||
boxlo = domain->boxlo[edim];
|
|
||||||
boxhi = domain->boxhi[edim];
|
|
||||||
double binsize = (boxhi-boxlo) / nbin;
|
|
||||||
slablo_lo = boxlo;
|
|
||||||
slablo_hi = boxlo + binsize;
|
|
||||||
slabhi_lo = boxlo + (nbin/2)*binsize;
|
|
||||||
slabhi_hi = boxlo + (nbin/2+1)*binsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
periodicity = domain->periodicity[edim];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixThermalConductivity::end_of_step()
|
|
||||||
{
|
|
||||||
int i,j,m,insert;
|
|
||||||
double coord,ke;
|
|
||||||
MPI_Status status;
|
|
||||||
struct {
|
|
||||||
double value;
|
|
||||||
int proc;
|
|
||||||
} mine[2],all[2];
|
|
||||||
|
|
||||||
// if box changes, recompute bounds of 2 slabs in edim
|
|
||||||
|
|
||||||
if (domain->box_change) {
|
|
||||||
prd = domain->prd[edim];
|
|
||||||
boxlo = domain->boxlo[edim];
|
|
||||||
boxhi = domain->boxhi[edim];
|
|
||||||
double binsize = (boxhi-boxlo) / nbin;
|
|
||||||
slablo_lo = boxlo;
|
|
||||||
slablo_hi = boxlo + binsize;
|
|
||||||
slabhi_lo = boxlo + (nbin/2)*binsize;
|
|
||||||
slabhi_hi = boxlo + (nbin/2+1)*binsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make 2 lists of up to nswap atoms
|
|
||||||
// hottest atoms in lo slab, coldest atoms in hi slab (really mid slab)
|
|
||||||
// lo slab list is sorted by hottest, hi slab is sorted by coldest
|
|
||||||
// map atoms back into periodic box if necessary
|
|
||||||
// insert = location in list to insert new atom
|
|
||||||
|
|
||||||
double **x = atom->x;
|
|
||||||
double **v = atom->v;
|
|
||||||
double *mass = atom->mass;
|
|
||||||
double *rmass = atom->rmass;
|
|
||||||
int *type = atom->type;
|
|
||||||
int *mask = atom->mask;
|
|
||||||
int nlocal = atom->nlocal;
|
|
||||||
|
|
||||||
nhi = nlo = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < nlocal; i++)
|
|
||||||
if (mask[i] & groupbit) {
|
|
||||||
coord = x[i][edim];
|
|
||||||
if (coord < boxlo && periodicity) coord += prd;
|
|
||||||
else if (coord >= boxhi && periodicity) coord -= prd;
|
|
||||||
|
|
||||||
if (coord >= slablo_lo && coord < slablo_hi) {
|
|
||||||
ke = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2];
|
|
||||||
if (rmass) ke *= 0.5*rmass[i];
|
|
||||||
else ke *= 0.5*mass[type[i]];
|
|
||||||
if (nlo < nswap || ke > ke_lo[nswap-1]) {
|
|
||||||
for (insert = nlo-1; insert >= 0; insert--)
|
|
||||||
if (ke < ke_lo[insert]) break;
|
|
||||||
insert++;
|
|
||||||
for (m = nlo-1; m >= insert; m--) {
|
|
||||||
ke_lo[m+1] = ke_lo[m];
|
|
||||||
index_lo[m+1] = index_lo[m];
|
|
||||||
}
|
|
||||||
ke_lo[insert] = ke;
|
|
||||||
index_lo[insert] = i;
|
|
||||||
if (nlo < nswap) nlo++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coord >= slabhi_lo && coord < slabhi_hi) {
|
|
||||||
ke = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2];
|
|
||||||
if (rmass) ke *= 0.5*rmass[i];
|
|
||||||
else ke *= 0.5*mass[type[i]];
|
|
||||||
if (nhi < nswap || ke < ke_hi[nswap-1]) {
|
|
||||||
for (insert = nhi-1; insert >= 0; insert--)
|
|
||||||
if (ke > ke_hi[insert]) break;
|
|
||||||
insert++;
|
|
||||||
for (m = nhi-1; m >= insert; m--) {
|
|
||||||
ke_hi[m+1] = ke_hi[m];
|
|
||||||
index_hi[m+1] = index_hi[m];
|
|
||||||
}
|
|
||||||
ke_hi[insert] = ke;
|
|
||||||
index_hi[insert] = i;
|
|
||||||
if (nhi < nswap) nhi++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop over nswap pairs
|
|
||||||
// pair 2 global atoms at beginning of sorted lo/hi slab lists via Allreduce
|
|
||||||
// BIG values are for procs with no atom to contribute
|
|
||||||
// use negative of hottest KE since is doing a MINLOC
|
|
||||||
// MINLOC also communicates which procs own them
|
|
||||||
// exchange kinetic energy between the 2 particles
|
|
||||||
// if I own both particles just swap, else point2point comm of velocities
|
|
||||||
|
|
||||||
double sbuf[4],rbuf[4],vcm[3];
|
|
||||||
double eswap = 0.0;
|
|
||||||
|
|
||||||
mine[0].proc = mine[1].proc = me;
|
|
||||||
int ilo = 0;
|
|
||||||
int ihi = 0;
|
|
||||||
|
|
||||||
for (m = 0; m < nswap; m++) {
|
|
||||||
if (ilo < nlo) mine[0].value = -ke_lo[ilo];
|
|
||||||
else mine[0].value = BIG;
|
|
||||||
if (ihi < nhi) mine[1].value = ke_hi[ihi];
|
|
||||||
else mine[1].value = BIG;
|
|
||||||
|
|
||||||
MPI_Allreduce(mine,all,2,MPI_DOUBLE_INT,MPI_MINLOC,world);
|
|
||||||
if (all[0].value == BIG || all[1].value == BIG) continue;
|
|
||||||
|
|
||||||
if (me == all[0].proc && me == all[1].proc) {
|
|
||||||
i = index_lo[ilo++];
|
|
||||||
j = index_hi[ihi++];
|
|
||||||
sbuf[0] = v[j][0];
|
|
||||||
sbuf[1] = v[j][1];
|
|
||||||
sbuf[2] = v[j][2];
|
|
||||||
if (rmass) sbuf[3] = rmass[j];
|
|
||||||
else sbuf[3] = mass[type[j]];
|
|
||||||
rbuf[0] = v[i][0];
|
|
||||||
rbuf[1] = v[i][1];
|
|
||||||
rbuf[2] = v[i][2];
|
|
||||||
if (rmass) rbuf[3] = rmass[i];
|
|
||||||
else rbuf[3] = mass[type[i]];
|
|
||||||
vcm[0] = (sbuf[3]*sbuf[0] + rbuf[3]*rbuf[0]) / (sbuf[3] + rbuf[3]);
|
|
||||||
vcm[1] = (sbuf[3]*sbuf[1] + rbuf[3]*rbuf[1]) / (sbuf[3] + rbuf[3]);
|
|
||||||
vcm[2] = (sbuf[3]*sbuf[2] + rbuf[3]*rbuf[2]) / (sbuf[3] + rbuf[3]);
|
|
||||||
v[j][0] = 2.0 * vcm[0] - sbuf[0];
|
|
||||||
v[j][1] = 2.0 * vcm[1] - sbuf[1];
|
|
||||||
v[j][2] = 2.0 * vcm[2] - sbuf[2];
|
|
||||||
eswap += sbuf[3] * (vcm[0] * (vcm[0] - sbuf[0]) +
|
|
||||||
vcm[1] * (vcm[1] - sbuf[1]) +
|
|
||||||
vcm[2] * (vcm[2] - sbuf[2]));
|
|
||||||
v[i][0] = 2.0 * vcm[0] - rbuf[0];
|
|
||||||
v[i][1] = 2.0 * vcm[1] - rbuf[1];
|
|
||||||
v[i][2] = 2.0 * vcm[2] - rbuf[2];
|
|
||||||
eswap -= rbuf[3] * (vcm[0] * (vcm[0] - rbuf[0]) +
|
|
||||||
vcm[1] * (vcm[1] - rbuf[1]) +
|
|
||||||
vcm[2] * (vcm[2] - rbuf[2]));
|
|
||||||
|
|
||||||
} else if (me == all[0].proc) {
|
|
||||||
j = index_lo[ilo++];
|
|
||||||
sbuf[0] = v[j][0];
|
|
||||||
sbuf[1] = v[j][1];
|
|
||||||
sbuf[2] = v[j][2];
|
|
||||||
if (rmass) sbuf[3] = rmass[j];
|
|
||||||
else sbuf[3] = mass[type[j]];
|
|
||||||
MPI_Sendrecv(sbuf,4,MPI_DOUBLE,all[1].proc,0,
|
|
||||||
rbuf,4,MPI_DOUBLE,all[1].proc,0,world,&status);
|
|
||||||
vcm[0] = (sbuf[3]*sbuf[0] + rbuf[3]*rbuf[0]) / (sbuf[3] + rbuf[3]);
|
|
||||||
vcm[1] = (sbuf[3]*sbuf[1] + rbuf[3]*rbuf[1]) / (sbuf[3] + rbuf[3]);
|
|
||||||
vcm[2] = (sbuf[3]*sbuf[2] + rbuf[3]*rbuf[2]) / (sbuf[3] + rbuf[3]);
|
|
||||||
v[j][0] = 2.0 * vcm[0] - sbuf[0];
|
|
||||||
v[j][1] = 2.0 * vcm[1] - sbuf[1];
|
|
||||||
v[j][2] = 2.0 * vcm[2] - sbuf[2];
|
|
||||||
eswap -= sbuf[3] * (vcm[0] * (vcm[0] - sbuf[0]) +
|
|
||||||
vcm[1] * (vcm[1] - sbuf[1]) +
|
|
||||||
vcm[2] * (vcm[2] - sbuf[2]));
|
|
||||||
|
|
||||||
} else if (me == all[1].proc) {
|
|
||||||
j = index_hi[ihi++];
|
|
||||||
sbuf[0] = v[j][0];
|
|
||||||
sbuf[1] = v[j][1];
|
|
||||||
sbuf[2] = v[j][2];
|
|
||||||
if (rmass) sbuf[3] = rmass[j];
|
|
||||||
else sbuf[3] = mass[type[j]];
|
|
||||||
MPI_Sendrecv(sbuf,4,MPI_DOUBLE,all[0].proc,0,
|
|
||||||
rbuf,4,MPI_DOUBLE,all[0].proc,0,world,&status);
|
|
||||||
vcm[0] = (sbuf[3]*sbuf[0] + rbuf[3]*rbuf[0]) / (sbuf[3] + rbuf[3]);
|
|
||||||
vcm[1] = (sbuf[3]*sbuf[1] + rbuf[3]*rbuf[1]) / (sbuf[3] + rbuf[3]);
|
|
||||||
vcm[2] = (sbuf[3]*sbuf[2] + rbuf[3]*rbuf[2]) / (sbuf[3] + rbuf[3]);
|
|
||||||
v[j][0] = 2.0 * vcm[0] - sbuf[0];
|
|
||||||
v[j][1] = 2.0 * vcm[1] - sbuf[1];
|
|
||||||
v[j][2] = 2.0 * vcm[2] - sbuf[2];
|
|
||||||
eswap += sbuf[3] * (vcm[0] * (vcm[0] - sbuf[0]) +
|
|
||||||
vcm[1] * (vcm[1] - sbuf[1]) +
|
|
||||||
vcm[2] * (vcm[2] - sbuf[2]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tally energy exchange from all swaps
|
|
||||||
|
|
||||||
double eswap_all;
|
|
||||||
MPI_Allreduce(&eswap,&eswap_all,1,MPI_DOUBLE,MPI_SUM,world);
|
|
||||||
e_exchange += force->mvv2e * eswap_all;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
double FixThermalConductivity::compute_scalar()
|
|
||||||
{
|
|
||||||
return e_exchange;
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#ifdef FIX_CLASS
|
|
||||||
|
|
||||||
FixStyle(thermal/conductivity,FixThermalConductivity)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifndef LMP_FIX_THERMAL_CONDUCTIVITY_H
|
|
||||||
#define LMP_FIX_THERMAL_CONDUCTIVITY_H
|
|
||||||
|
|
||||||
#include "fix.h"
|
|
||||||
|
|
||||||
namespace LAMMPS_NS {
|
|
||||||
|
|
||||||
class FixThermalConductivity : public Fix {
|
|
||||||
public:
|
|
||||||
FixThermalConductivity(class LAMMPS *, int, char **);
|
|
||||||
~FixThermalConductivity();
|
|
||||||
int setmask();
|
|
||||||
void init();
|
|
||||||
void end_of_step();
|
|
||||||
double compute_scalar();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int me;
|
|
||||||
int edim,nbin,periodicity;
|
|
||||||
int nswap;
|
|
||||||
double prd,boxlo,boxhi;
|
|
||||||
double slablo_lo,slablo_hi,slabhi_lo,slabhi_hi;
|
|
||||||
double e_exchange;
|
|
||||||
|
|
||||||
int nlo,nhi;
|
|
||||||
int *index_lo,*index_hi;
|
|
||||||
double *ke_lo,*ke_hi;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ERROR/WARNING messages:
|
|
||||||
|
|
||||||
E: Illegal ... command
|
|
||||||
|
|
||||||
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: Fix thermal/conductivity swap value must be positive
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
W: Fix thermal/conductivity comes before fix ave/spatial
|
|
||||||
|
|
||||||
The order of these 2 fixes in your input script is such that fix
|
|
||||||
thermal/conductivity comes first. If you are using fix ave/spatial to
|
|
||||||
measure the temperature profile induced by fix viscosity, then this
|
|
||||||
may cause a glitch in the profile since you are averaging immediately
|
|
||||||
after swaps have occurred. Flipping the order of the 2 fixes
|
|
||||||
typically helps.
|
|
||||||
|
|
||||||
*/
|
|
685
src/fix_ttm.cpp
685
src/fix_ttm.cpp
|
@ -1,685 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
Contributing authors: Paul Crozier (SNL)
|
|
||||||
Carolyn Phillips (University of Michigan)
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#include "lmptype.h"
|
|
||||||
#include "mpi.h"
|
|
||||||
#include "math.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include "stdlib.h"
|
|
||||||
#include "fix_ttm.h"
|
|
||||||
#include "atom.h"
|
|
||||||
#include "force.h"
|
|
||||||
#include "update.h"
|
|
||||||
#include "domain.h"
|
|
||||||
#include "region.h"
|
|
||||||
#include "respa.h"
|
|
||||||
#include "comm.h"
|
|
||||||
#include "random_mars.h"
|
|
||||||
#include "memory.h"
|
|
||||||
#include "error.h"
|
|
||||||
|
|
||||||
using namespace LAMMPS_NS;
|
|
||||||
using namespace FixConst;
|
|
||||||
|
|
||||||
#define MAXLINE 1024
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
FixTTM::FixTTM(LAMMPS *lmp, int narg, char **arg) :
|
|
||||||
Fix(lmp, narg, arg)
|
|
||||||
{
|
|
||||||
if (narg < 15) error->all(FLERR,"Illegal fix ttm command");
|
|
||||||
|
|
||||||
vector_flag = 1;
|
|
||||||
size_vector = 2;
|
|
||||||
global_freq = 1;
|
|
||||||
extvector = 1;
|
|
||||||
nevery = 1;
|
|
||||||
restart_peratom = 1;
|
|
||||||
restart_global = 1;
|
|
||||||
|
|
||||||
seed = force->inumeric(FLERR,arg[3]);
|
|
||||||
electronic_specific_heat = force->numeric(FLERR,arg[4]);
|
|
||||||
electronic_density = force->numeric(FLERR,arg[5]);
|
|
||||||
electronic_thermal_conductivity = force->numeric(FLERR,arg[6]);
|
|
||||||
gamma_p = force->numeric(FLERR,arg[7]);
|
|
||||||
gamma_s = force->numeric(FLERR,arg[8]);
|
|
||||||
v_0 = force->numeric(FLERR,arg[9]);
|
|
||||||
nxnodes = force->inumeric(FLERR,arg[10]);
|
|
||||||
nynodes = force->inumeric(FLERR,arg[11]);
|
|
||||||
nznodes = force->inumeric(FLERR,arg[12]);
|
|
||||||
|
|
||||||
fpr = fopen(arg[13],"r");
|
|
||||||
if (fpr == NULL) {
|
|
||||||
char str[128];
|
|
||||||
sprintf(str,"Cannot open file %s",arg[13]);
|
|
||||||
error->one(FLERR,str);
|
|
||||||
}
|
|
||||||
|
|
||||||
nfileevery = force->inumeric(FLERR,arg[14]);
|
|
||||||
|
|
||||||
if (nfileevery) {
|
|
||||||
if (narg != 16) error->all(FLERR,"Illegal fix ttm command");
|
|
||||||
MPI_Comm_rank(world,&me);
|
|
||||||
if (me == 0) {
|
|
||||||
fp = fopen(arg[15],"w");
|
|
||||||
if (fp == NULL) {
|
|
||||||
char str[128];
|
|
||||||
sprintf(str,"Cannot open fix ttm file %s",arg[15]);
|
|
||||||
error->one(FLERR,str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// error check
|
|
||||||
|
|
||||||
if (seed <= 0) error->all(FLERR,"Invalid random number seed in fix ttm command");
|
|
||||||
if (electronic_specific_heat <= 0.0)
|
|
||||||
error->all(FLERR,"Fix ttm electronic_specific_heat must be > 0.0");
|
|
||||||
if (electronic_density <= 0.0)
|
|
||||||
error->all(FLERR,"Fix ttm electronic_density must be > 0.0");
|
|
||||||
if (electronic_thermal_conductivity < 0.0)
|
|
||||||
error->all(FLERR,"Fix ttm electronic_thermal_conductivity must be >= 0.0");
|
|
||||||
if (gamma_p <= 0.0) error->all(FLERR,"Fix ttm gamma_p must be > 0.0");
|
|
||||||
if (gamma_s < 0.0) error->all(FLERR,"Fix ttm gamma_s must be >= 0.0");
|
|
||||||
if (v_0 < 0.0) error->all(FLERR,"Fix ttm v_0 must be >= 0.0");
|
|
||||||
if (nxnodes <= 0 || nynodes <= 0 || nznodes <= 0)
|
|
||||||
error->all(FLERR,"Fix ttm number of nodes must be > 0");
|
|
||||||
|
|
||||||
v_0_sq = v_0*v_0;
|
|
||||||
|
|
||||||
// initialize Marsaglia RNG with processor-unique seed
|
|
||||||
|
|
||||||
random = new RanMars(lmp,seed + comm->me);
|
|
||||||
|
|
||||||
// allocate per-type arrays for force prefactors
|
|
||||||
|
|
||||||
gfactor1 = new double[atom->ntypes+1];
|
|
||||||
gfactor2 = new double[atom->ntypes+1];
|
|
||||||
|
|
||||||
// allocate 3d grid variables
|
|
||||||
|
|
||||||
total_nnodes = nxnodes*nynodes*nznodes;
|
|
||||||
|
|
||||||
memory->create(nsum,nxnodes,nynodes,nznodes,"ttm:nsum");
|
|
||||||
memory->create(nsum_all,nxnodes,nynodes,nznodes,"ttm:nsum_all");
|
|
||||||
memory->create(T_initial_set,nxnodes,nynodes,nznodes,"ttm:T_initial_set");
|
|
||||||
memory->create(sum_vsq,nxnodes,nynodes,nznodes,"ttm:sum_vsq");
|
|
||||||
memory->create(sum_mass_vsq,nxnodes,nynodes,nznodes,"ttm:sum_mass_vsq");
|
|
||||||
memory->create(sum_vsq_all,nxnodes,nynodes,nznodes,"ttm:sum_vsq_all");
|
|
||||||
memory->create(sum_mass_vsq_all,nxnodes,nynodes,nznodes,
|
|
||||||
"ttm:sum_mass_vsq_all");
|
|
||||||
memory->create(T_electron_old,nxnodes,nynodes,nznodes,"ttm:T_electron_old");
|
|
||||||
memory->create(T_electron,nxnodes,nynodes,nznodes,"ttm:T_electron");
|
|
||||||
memory->create(net_energy_transfer,nxnodes,nynodes,nznodes,
|
|
||||||
"TTM:net_energy_transfer");
|
|
||||||
memory->create(net_energy_transfer_all,nxnodes,nynodes,nznodes,
|
|
||||||
"TTM:net_energy_transfer_all");
|
|
||||||
|
|
||||||
flangevin = NULL;
|
|
||||||
grow_arrays(atom->nmax);
|
|
||||||
|
|
||||||
// zero out the flangevin array
|
|
||||||
|
|
||||||
for (int i = 0; i < atom->nmax; i++) {
|
|
||||||
flangevin[i][0] = 0;
|
|
||||||
flangevin[i][1] = 0;
|
|
||||||
flangevin[i][2] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
atom->add_callback(0);
|
|
||||||
atom->add_callback(1);
|
|
||||||
|
|
||||||
// set initial electron temperatures from user input file
|
|
||||||
|
|
||||||
if (me == 0) read_initial_electron_temperatures();
|
|
||||||
MPI_Bcast(&T_electron[0][0][0],total_nnodes,MPI_DOUBLE,0,world);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
FixTTM::~FixTTM()
|
|
||||||
{
|
|
||||||
if (nfileevery && me == 0) fclose(fp);
|
|
||||||
|
|
||||||
delete random;
|
|
||||||
|
|
||||||
delete [] gfactor1;
|
|
||||||
delete [] gfactor2;
|
|
||||||
|
|
||||||
memory->destroy(nsum);
|
|
||||||
memory->destroy(nsum_all);
|
|
||||||
memory->destroy(T_initial_set);
|
|
||||||
memory->destroy(sum_vsq);
|
|
||||||
memory->destroy(sum_mass_vsq);
|
|
||||||
memory->destroy(sum_vsq_all);
|
|
||||||
memory->destroy(sum_mass_vsq_all);
|
|
||||||
memory->destroy(T_electron_old);
|
|
||||||
memory->destroy(T_electron);
|
|
||||||
memory->destroy(flangevin);
|
|
||||||
memory->destroy(net_energy_transfer);
|
|
||||||
memory->destroy(net_energy_transfer_all);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
int FixTTM::setmask()
|
|
||||||
{
|
|
||||||
int mask = 0;
|
|
||||||
mask |= POST_FORCE;
|
|
||||||
mask |= POST_FORCE_RESPA;
|
|
||||||
mask |= END_OF_STEP;
|
|
||||||
return mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::init()
|
|
||||||
{
|
|
||||||
if (domain->dimension == 2)
|
|
||||||
error->all(FLERR,"Cannot use fix ttm with 2d simulation");
|
|
||||||
if (domain->nonperiodic != 0)
|
|
||||||
error->all(FLERR,"Cannot use nonperiodic boundares with fix ttm");
|
|
||||||
if (domain->triclinic)
|
|
||||||
error->all(FLERR,"Cannot use fix ttm with triclinic box");
|
|
||||||
|
|
||||||
// set force prefactors
|
|
||||||
|
|
||||||
for (int i = 1; i <= atom->ntypes; i++) {
|
|
||||||
gfactor1[i] = - gamma_p / force->ftm2v;
|
|
||||||
gfactor2[i] =
|
|
||||||
sqrt(24.0*force->boltz*gamma_p/update->dt/force->mvv2e) / force->ftm2v;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++)
|
|
||||||
net_energy_transfer_all[ixnode][iynode][iznode] = 0;
|
|
||||||
|
|
||||||
if (strstr(update->integrate_style,"respa"))
|
|
||||||
nlevels_respa = ((Respa *) update->integrate)->nlevels;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::setup(int vflag)
|
|
||||||
{
|
|
||||||
if (strstr(update->integrate_style,"verlet"))
|
|
||||||
post_force_setup(vflag);
|
|
||||||
else {
|
|
||||||
((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1);
|
|
||||||
post_force_respa_setup(vflag,nlevels_respa-1,0);
|
|
||||||
((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::post_force(int vflag)
|
|
||||||
{
|
|
||||||
double **x = atom->x;
|
|
||||||
double **v = atom->v;
|
|
||||||
double **f = atom->f;
|
|
||||||
int *type = atom->type;
|
|
||||||
int *mask = atom->mask;
|
|
||||||
int nlocal = atom->nlocal;
|
|
||||||
|
|
||||||
double gamma1,gamma2;
|
|
||||||
|
|
||||||
// apply damping and thermostat to all atoms in fix group
|
|
||||||
|
|
||||||
for (int i = 0; i < nlocal; i++) {
|
|
||||||
if (mask[i] & groupbit) {
|
|
||||||
|
|
||||||
double xscale = (x[i][0] - domain->boxlo[0])/domain->xprd;
|
|
||||||
double yscale = (x[i][1] - domain->boxlo[1])/domain->yprd;
|
|
||||||
double zscale = (x[i][2] - domain->boxlo[2])/domain->zprd;
|
|
||||||
int ixnode = static_cast<int>(xscale*nxnodes);
|
|
||||||
int iynode = static_cast<int>(yscale*nynodes);
|
|
||||||
int iznode = static_cast<int>(zscale*nznodes);
|
|
||||||
while (ixnode > nxnodes-1) ixnode -= nxnodes;
|
|
||||||
while (iynode > nynodes-1) iynode -= nynodes;
|
|
||||||
while (iznode > nznodes-1) iznode -= nznodes;
|
|
||||||
while (ixnode < 0) ixnode += nxnodes;
|
|
||||||
while (iynode < 0) iynode += nynodes;
|
|
||||||
while (iznode < 0) iznode += nznodes;
|
|
||||||
|
|
||||||
if (T_electron[ixnode][iynode][iznode] < 0)
|
|
||||||
error->all(FLERR,"Electronic temperature dropped below zero");
|
|
||||||
|
|
||||||
double tsqrt = sqrt(T_electron[ixnode][iynode][iznode]);
|
|
||||||
|
|
||||||
gamma1 = gfactor1[type[i]];
|
|
||||||
double vsq = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2];
|
|
||||||
if (vsq > v_0_sq) gamma1 *= (gamma_p + gamma_s)/gamma_p;
|
|
||||||
gamma2 = gfactor2[type[i]] * tsqrt;
|
|
||||||
|
|
||||||
flangevin[i][0] = gamma1*v[i][0] + gamma2*(random->uniform()-0.5);
|
|
||||||
flangevin[i][1] = gamma1*v[i][1] + gamma2*(random->uniform()-0.5);
|
|
||||||
flangevin[i][2] = gamma1*v[i][2] + gamma2*(random->uniform()-0.5);
|
|
||||||
|
|
||||||
f[i][0] += flangevin[i][0];
|
|
||||||
f[i][1] += flangevin[i][1];
|
|
||||||
f[i][2] += flangevin[i][2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::post_force_setup(int vflag)
|
|
||||||
{
|
|
||||||
double **f = atom->f;
|
|
||||||
int *mask = atom->mask;
|
|
||||||
int nlocal = atom->nlocal;
|
|
||||||
|
|
||||||
// apply langevin forces that have been stored from previous run
|
|
||||||
|
|
||||||
for (int i = 0; i < nlocal; i++) {
|
|
||||||
if (mask[i] & groupbit) {
|
|
||||||
f[i][0] += flangevin[i][0];
|
|
||||||
f[i][1] += flangevin[i][1];
|
|
||||||
f[i][2] += flangevin[i][2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::post_force_respa(int vflag, int ilevel, int iloop)
|
|
||||||
{
|
|
||||||
if (ilevel == nlevels_respa-1) post_force(vflag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::post_force_respa_setup(int vflag, int ilevel, int iloop)
|
|
||||||
{
|
|
||||||
if (ilevel == nlevels_respa-1) post_force_setup(vflag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::reset_dt()
|
|
||||||
{
|
|
||||||
for (int i = 1; i <= atom->ntypes; i++)
|
|
||||||
gfactor2[i] =
|
|
||||||
sqrt(24.0*force->boltz*gamma_p/update->dt/force->mvv2e) / force->ftm2v;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
read in initial electron temperatures from a user-specified file
|
|
||||||
only called by proc 0
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::read_initial_electron_temperatures()
|
|
||||||
{
|
|
||||||
char line[MAXLINE];
|
|
||||||
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++)
|
|
||||||
T_initial_set[ixnode][iynode][iznode] = 0;
|
|
||||||
|
|
||||||
// read initial electron temperature values from file
|
|
||||||
|
|
||||||
int ixnode,iynode,iznode;
|
|
||||||
double T_tmp;
|
|
||||||
while (1) {
|
|
||||||
if (fgets(line,MAXLINE,fpr) == NULL) break;
|
|
||||||
sscanf(line,"%d %d %d %lg",&ixnode,&iynode,&iznode,&T_tmp);
|
|
||||||
if (T_tmp < 0.0) error->one(FLERR,"Fix ttm electron temperatures must be > 0.0");
|
|
||||||
T_electron[ixnode][iynode][iznode] = T_tmp;
|
|
||||||
T_initial_set[ixnode][iynode][iznode] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++)
|
|
||||||
if (T_initial_set[ixnode][iynode][iznode] == 0)
|
|
||||||
error->one(FLERR,"Initial temperatures not all set in fix ttm");
|
|
||||||
|
|
||||||
// close file
|
|
||||||
|
|
||||||
fclose(fpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::end_of_step()
|
|
||||||
{
|
|
||||||
double **x = atom->x;
|
|
||||||
double **v = atom->v;
|
|
||||||
double *mass = atom->mass;
|
|
||||||
double *rmass = atom->rmass;
|
|
||||||
int *type = atom->type;
|
|
||||||
int *mask = atom->mask;
|
|
||||||
int nlocal = atom->nlocal;
|
|
||||||
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++)
|
|
||||||
net_energy_transfer[ixnode][iynode][iznode] = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < nlocal; i++)
|
|
||||||
if (mask[i] & groupbit) {
|
|
||||||
double xscale = (x[i][0] - domain->boxlo[0])/domain->xprd;
|
|
||||||
double yscale = (x[i][1] - domain->boxlo[1])/domain->yprd;
|
|
||||||
double zscale = (x[i][2] - domain->boxlo[2])/domain->zprd;
|
|
||||||
int ixnode = static_cast<int>(xscale*nxnodes);
|
|
||||||
int iynode = static_cast<int>(yscale*nynodes);
|
|
||||||
int iznode = static_cast<int>(zscale*nznodes);
|
|
||||||
while (ixnode > nxnodes-1) ixnode -= nxnodes;
|
|
||||||
while (iynode > nynodes-1) iynode -= nynodes;
|
|
||||||
while (iznode > nznodes-1) iznode -= nznodes;
|
|
||||||
while (ixnode < 0) ixnode += nxnodes;
|
|
||||||
while (iynode < 0) iynode += nynodes;
|
|
||||||
while (iznode < 0) iznode += nznodes;
|
|
||||||
net_energy_transfer[ixnode][iynode][iznode] +=
|
|
||||||
(flangevin[i][0]*v[i][0] + flangevin[i][1]*v[i][1] +
|
|
||||||
flangevin[i][2]*v[i][2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
MPI_Allreduce(&net_energy_transfer[0][0][0],
|
|
||||||
&net_energy_transfer_all[0][0][0],
|
|
||||||
total_nnodes,MPI_DOUBLE,MPI_SUM,world);
|
|
||||||
|
|
||||||
double dx = domain->xprd/nxnodes;
|
|
||||||
double dy = domain->yprd/nynodes;
|
|
||||||
double dz = domain->zprd/nznodes;
|
|
||||||
double del_vol = dx*dy*dz;
|
|
||||||
|
|
||||||
// num_inner_timesteps = # of inner steps (thermal solves)
|
|
||||||
// required this MD step to maintain a stable explicit solve
|
|
||||||
|
|
||||||
int num_inner_timesteps = 1;
|
|
||||||
double inner_dt = update->dt;
|
|
||||||
double stability_criterion = 1.0 -
|
|
||||||
2.0*inner_dt/(electronic_specific_heat*electronic_density) *
|
|
||||||
(electronic_thermal_conductivity*(1.0/dx/dx + 1.0/dy/dy + 1.0/dz/dz));
|
|
||||||
if (stability_criterion < 0.0) {
|
|
||||||
inner_dt = 0.5*(electronic_specific_heat*electronic_density) /
|
|
||||||
(electronic_thermal_conductivity*(1.0/dx/dx + 1.0/dy/dy + 1.0/dz/dz));
|
|
||||||
num_inner_timesteps = static_cast<int>(update->dt/inner_dt) + 1;
|
|
||||||
inner_dt = update->dt/double(num_inner_timesteps);
|
|
||||||
if (num_inner_timesteps > 1000000)
|
|
||||||
error->warning(FLERR,"Too many inner timesteps in fix ttm",0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int ith_inner_timestep = 0; ith_inner_timestep < num_inner_timesteps;
|
|
||||||
ith_inner_timestep++) {
|
|
||||||
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++)
|
|
||||||
T_electron_old[ixnode][iynode][iznode] =
|
|
||||||
T_electron[ixnode][iynode][iznode];
|
|
||||||
|
|
||||||
// compute new electron T profile
|
|
||||||
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++) {
|
|
||||||
int right_xnode = ixnode + 1;
|
|
||||||
int right_ynode = iynode + 1;
|
|
||||||
int right_znode = iznode + 1;
|
|
||||||
if (right_xnode == nxnodes) right_xnode = 0;
|
|
||||||
if (right_ynode == nynodes) right_ynode = 0;
|
|
||||||
if (right_znode == nznodes) right_znode = 0;
|
|
||||||
int left_xnode = ixnode - 1;
|
|
||||||
int left_ynode = iynode - 1;
|
|
||||||
int left_znode = iznode - 1;
|
|
||||||
if (left_xnode == -1) left_xnode = nxnodes - 1;
|
|
||||||
if (left_ynode == -1) left_ynode = nynodes - 1;
|
|
||||||
if (left_znode == -1) left_znode = nznodes - 1;
|
|
||||||
T_electron[ixnode][iynode][iznode] =
|
|
||||||
T_electron_old[ixnode][iynode][iznode] +
|
|
||||||
inner_dt/(electronic_specific_heat*electronic_density) *
|
|
||||||
(electronic_thermal_conductivity *
|
|
||||||
((T_electron_old[right_xnode][iynode][iznode] +
|
|
||||||
T_electron_old[left_xnode][iynode][iznode] -
|
|
||||||
2*T_electron_old[ixnode][iynode][iznode])/dx/dx +
|
|
||||||
(T_electron_old[ixnode][right_ynode][iznode] +
|
|
||||||
T_electron_old[ixnode][left_ynode][iznode] -
|
|
||||||
2*T_electron_old[ixnode][iynode][iznode])/dy/dy +
|
|
||||||
(T_electron_old[ixnode][iynode][right_znode] +
|
|
||||||
T_electron_old[ixnode][iynode][left_znode] -
|
|
||||||
2*T_electron_old[ixnode][iynode][iznode])/dz/dz) -
|
|
||||||
(net_energy_transfer_all[ixnode][iynode][iznode])/del_vol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// output nodal temperatures for current timestep
|
|
||||||
|
|
||||||
if ((nfileevery) && !(update->ntimestep % nfileevery)) {
|
|
||||||
|
|
||||||
// compute atomic Ta for each grid point
|
|
||||||
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++) {
|
|
||||||
nsum[ixnode][iynode][iznode] = 0;
|
|
||||||
nsum_all[ixnode][iynode][iznode] = 0;
|
|
||||||
sum_vsq[ixnode][iynode][iznode] = 0.0;
|
|
||||||
sum_mass_vsq[ixnode][iynode][iznode] = 0.0;
|
|
||||||
sum_vsq_all[ixnode][iynode][iznode] = 0.0;
|
|
||||||
sum_mass_vsq_all[ixnode][iynode][iznode] = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
double massone;
|
|
||||||
for (int i = 0; i < nlocal; i++)
|
|
||||||
if (mask[i] & groupbit) {
|
|
||||||
if (rmass) massone = rmass[i];
|
|
||||||
else massone = mass[type[i]];
|
|
||||||
double xscale = (x[i][0] - domain->boxlo[0])/domain->xprd;
|
|
||||||
double yscale = (x[i][1] - domain->boxlo[1])/domain->yprd;
|
|
||||||
double zscale = (x[i][2] - domain->boxlo[2])/domain->zprd;
|
|
||||||
int ixnode = static_cast<int>(xscale*nxnodes);
|
|
||||||
int iynode = static_cast<int>(yscale*nynodes);
|
|
||||||
int iznode = static_cast<int>(zscale*nznodes);
|
|
||||||
while (ixnode > nxnodes-1) ixnode -= nxnodes;
|
|
||||||
while (iynode > nynodes-1) iynode -= nynodes;
|
|
||||||
while (iznode > nznodes-1) iznode -= nznodes;
|
|
||||||
while (ixnode < 0) ixnode += nxnodes;
|
|
||||||
while (iynode < 0) iynode += nynodes;
|
|
||||||
while (iznode < 0) iznode += nznodes;
|
|
||||||
double vsq = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2];
|
|
||||||
nsum[ixnode][iynode][iznode] += 1;
|
|
||||||
sum_vsq[ixnode][iynode][iznode] += vsq;
|
|
||||||
sum_mass_vsq[ixnode][iynode][iznode] += massone*vsq;
|
|
||||||
}
|
|
||||||
|
|
||||||
MPI_Allreduce(&nsum[0][0][0],&nsum_all[0][0][0],total_nnodes,
|
|
||||||
MPI_INT,MPI_SUM,world);
|
|
||||||
MPI_Allreduce(&sum_vsq[0][0][0],&sum_vsq_all[0][0][0],total_nnodes,
|
|
||||||
MPI_DOUBLE,MPI_SUM,world);
|
|
||||||
MPI_Allreduce(&sum_mass_vsq[0][0][0],&sum_mass_vsq_all[0][0][0],
|
|
||||||
total_nnodes,MPI_DOUBLE,MPI_SUM,world);
|
|
||||||
|
|
||||||
if (me == 0) {
|
|
||||||
fprintf(fp,BIGINT_FORMAT,update->ntimestep);
|
|
||||||
|
|
||||||
double T_a;
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++) {
|
|
||||||
T_a = 0;
|
|
||||||
if (nsum_all[ixnode][iynode][iznode] > 0)
|
|
||||||
T_a = sum_mass_vsq_all[ixnode][iynode][iznode]/
|
|
||||||
(3.0*force->boltz*nsum_all[ixnode][iynode][iznode]/force->mvv2e);
|
|
||||||
fprintf(fp," %f",T_a);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp,"\t");
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++)
|
|
||||||
fprintf(fp,"%f ",T_electron[ixnode][iynode][iznode]);
|
|
||||||
fprintf(fp,"\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
memory usage of 3d grid
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
double FixTTM::memory_usage()
|
|
||||||
{
|
|
||||||
double bytes = 0.0;
|
|
||||||
bytes += 5*total_nnodes * sizeof(int);
|
|
||||||
bytes += 14*total_nnodes * sizeof(double);
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::grow_arrays(int ngrow)
|
|
||||||
{
|
|
||||||
|
|
||||||
memory->grow(flangevin,ngrow,3,"TTM:flangevin");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
return the energy of the electronic subsystem or the net_energy transfer
|
|
||||||
between the subsystems
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
double FixTTM::compute_vector(int n)
|
|
||||||
{
|
|
||||||
double e_energy = 0.0;
|
|
||||||
double transfer_energy = 0.0;
|
|
||||||
|
|
||||||
double dx = domain->xprd/nxnodes;
|
|
||||||
double dy = domain->yprd/nynodes;
|
|
||||||
double dz = domain->zprd/nznodes;
|
|
||||||
double del_vol = dx*dy*dz;
|
|
||||||
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++) {
|
|
||||||
e_energy +=
|
|
||||||
T_electron[ixnode][iynode][iznode]*electronic_specific_heat*
|
|
||||||
electronic_density*del_vol;
|
|
||||||
transfer_energy +=
|
|
||||||
net_energy_transfer_all[ixnode][iynode][iznode]*update->dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n == 0) return e_energy;
|
|
||||||
if (n == 1) return transfer_energy;
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
pack entire state of Fix into one write
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::write_restart(FILE *fp)
|
|
||||||
{
|
|
||||||
double *rlist;
|
|
||||||
memory->create(rlist,nxnodes*nynodes*nznodes+1,"TTM:rlist");
|
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
rlist[n++] = seed;
|
|
||||||
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++)
|
|
||||||
rlist[n++] = T_electron[ixnode][iynode][iznode];
|
|
||||||
|
|
||||||
if (comm->me == 0) {
|
|
||||||
int size = n * sizeof(double);
|
|
||||||
fwrite(&size,sizeof(int),1,fp);
|
|
||||||
fwrite(rlist,sizeof(double),n,fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
memory->destroy(rlist);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
use state info from restart file to restart the Fix
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::restart(char *buf)
|
|
||||||
{
|
|
||||||
int n = 0;
|
|
||||||
double *rlist = (double *) buf;
|
|
||||||
|
|
||||||
// the seed must be changed from the initial seed
|
|
||||||
|
|
||||||
seed = static_cast<int> (0.5*rlist[n++]);
|
|
||||||
|
|
||||||
for (int ixnode = 0; ixnode < nxnodes; ixnode++)
|
|
||||||
for (int iynode = 0; iynode < nynodes; iynode++)
|
|
||||||
for (int iznode = 0; iznode < nznodes; iznode++)
|
|
||||||
T_electron[ixnode][iynode][iznode] = rlist[n++];
|
|
||||||
|
|
||||||
delete random;
|
|
||||||
random = new RanMars(lmp,seed+comm->me);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
pack values in local atom-based arrays for restart file
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
int FixTTM::pack_restart(int i, double *buf)
|
|
||||||
{
|
|
||||||
buf[0] = 4;
|
|
||||||
buf[1] = flangevin[i][0];
|
|
||||||
buf[2] = flangevin[i][1];
|
|
||||||
buf[3] = flangevin[i][2];
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
unpack values from atom->extra array to restart the fix
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixTTM::unpack_restart(int nlocal, int nth)
|
|
||||||
{
|
|
||||||
double **extra = atom->extra;
|
|
||||||
|
|
||||||
// skip to Nth set of extra values
|
|
||||||
|
|
||||||
int m = 0;
|
|
||||||
for (int i = 0; i < nth; i++) m += static_cast<int> (extra[nlocal][m]);
|
|
||||||
m++;
|
|
||||||
|
|
||||||
flangevin[nlocal][0] = extra[nlocal][m++];
|
|
||||||
flangevin[nlocal][1] = extra[nlocal][m++];
|
|
||||||
flangevin[nlocal][2] = extra[nlocal][m++];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
maxsize of any atom's restart data
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
int FixTTM::maxsize_restart()
|
|
||||||
{
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
size of atom nlocal's restart data
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
int FixTTM::size_restart(int nlocal)
|
|
||||||
{
|
|
||||||
return 4;
|
|
||||||
}
|
|
156
src/fix_ttm.h
156
src/fix_ttm.h
|
@ -1,156 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#ifdef FIX_CLASS
|
|
||||||
|
|
||||||
FixStyle(ttm,FixTTM)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifndef LMP_FIX_TTM_H
|
|
||||||
#define LMP_FIX_TTM_H
|
|
||||||
|
|
||||||
#include "fix.h"
|
|
||||||
|
|
||||||
namespace LAMMPS_NS {
|
|
||||||
|
|
||||||
class FixTTM : public Fix {
|
|
||||||
public:
|
|
||||||
FixTTM(class LAMMPS *, int, char **);
|
|
||||||
~FixTTM();
|
|
||||||
int setmask();
|
|
||||||
void init();
|
|
||||||
void setup(int);
|
|
||||||
void post_force(int);
|
|
||||||
void post_force_respa(int, int, int);
|
|
||||||
void post_force_setup(int);
|
|
||||||
void post_force_respa_setup(int, int, int);
|
|
||||||
void end_of_step();
|
|
||||||
void reset_dt();
|
|
||||||
void write_restart(FILE *);
|
|
||||||
void restart(char *);
|
|
||||||
int pack_restart(int, double *);
|
|
||||||
void unpack_restart(int, int);
|
|
||||||
int size_restart(int);
|
|
||||||
int maxsize_restart();
|
|
||||||
double memory_usage();
|
|
||||||
void grow_arrays(int);
|
|
||||||
double compute_vector(int);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int me;
|
|
||||||
int nfileevery;
|
|
||||||
int nlevels_respa;
|
|
||||||
int seed;
|
|
||||||
class RanMars *random;
|
|
||||||
FILE *fp,*fpr;
|
|
||||||
int nxnodes,nynodes,nznodes,total_nnodes;
|
|
||||||
int ***nsum;
|
|
||||||
int ***nsum_all,***T_initial_set;
|
|
||||||
double *gfactor1,*gfactor2,*ratio;
|
|
||||||
double **flangevin;
|
|
||||||
double ***T_electron,***T_electron_old;
|
|
||||||
double ***sum_vsq,***sum_mass_vsq;
|
|
||||||
double ***sum_vsq_all,***sum_mass_vsq_all;
|
|
||||||
double ***net_energy_transfer,***net_energy_transfer_all;
|
|
||||||
double electronic_specific_heat,electronic_density;
|
|
||||||
double electronic_thermal_conductivity;
|
|
||||||
double gamma_p,gamma_s,v_0,v_0_sq;
|
|
||||||
|
|
||||||
void read_initial_electron_temperatures();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ERROR/WARNING messages:
|
|
||||||
|
|
||||||
E: Illegal ... command
|
|
||||||
|
|
||||||
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: Cannot open file %s
|
|
||||||
|
|
||||||
The specified file cannot be opened. Check that the path and name are
|
|
||||||
correct.
|
|
||||||
|
|
||||||
E: Cannot open fix ttm file %s
|
|
||||||
|
|
||||||
The output file for the fix ttm command cannot be opened. Check that
|
|
||||||
the path and name are correct.
|
|
||||||
|
|
||||||
E: Invalid random number seed in fix ttm command
|
|
||||||
|
|
||||||
Random number seed must be > 0.
|
|
||||||
|
|
||||||
E: Fix ttm electronic_specific_heat must be > 0.0
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Fix ttm electronic_density must be > 0.0
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Fix ttm electronic_thermal_conductivity must be >= 0.0
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Fix ttm gamma_p must be > 0.0
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Fix ttm gamma_s must be >= 0.0
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Fix ttm v_0 must be >= 0.0
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Fix ttm number of nodes must be > 0
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Cannot use fix ttm with 2d simulation
|
|
||||||
|
|
||||||
This is a current restriction of this fix due to the grid it creates.
|
|
||||||
|
|
||||||
E: Cannot use nonperiodic boundares with fix ttm
|
|
||||||
|
|
||||||
This fix requires a fully periodic simulation box.
|
|
||||||
|
|
||||||
E: Cannot use fix ttm with triclinic box
|
|
||||||
|
|
||||||
This is a current restriction of this fix due to the grid it creates.
|
|
||||||
|
|
||||||
E: Electronic temperature dropped below zero
|
|
||||||
|
|
||||||
Something has gone wrong with the fix ttm electron temperature model.
|
|
||||||
|
|
||||||
E: Fix ttm electron temperatures must be > 0.0
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Initial temperatures not all set in fix ttm
|
|
||||||
|
|
||||||
Self-explantory.
|
|
||||||
|
|
||||||
W: Too many inner timesteps in fix ttm
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
*/
|
|
|
@ -1,309 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
Contributing author: Craig Tenney (UND) added support
|
|
||||||
for swapping atoms of different masses
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#include "math.h"
|
|
||||||
#include "mpi.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include "stdlib.h"
|
|
||||||
#include "fix_viscosity.h"
|
|
||||||
#include "atom.h"
|
|
||||||
#include "domain.h"
|
|
||||||
#include "modify.h"
|
|
||||||
#include "error.h"
|
|
||||||
#include "force.h"
|
|
||||||
|
|
||||||
using namespace LAMMPS_NS;
|
|
||||||
using namespace FixConst;
|
|
||||||
|
|
||||||
// needs to be big, but not so big that lose precision when subtract velocity
|
|
||||||
|
|
||||||
#define BIG 1.0e10
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
FixViscosity::FixViscosity(LAMMPS *lmp, int narg, char **arg) :
|
|
||||||
Fix(lmp, narg, arg)
|
|
||||||
{
|
|
||||||
if (narg < 7) error->all(FLERR,"Illegal fix viscosity command");
|
|
||||||
|
|
||||||
MPI_Comm_rank(world,&me);
|
|
||||||
|
|
||||||
nevery = force->inumeric(FLERR,arg[3]);
|
|
||||||
if (nevery <= 0) error->all(FLERR,"Illegal fix viscosity command");
|
|
||||||
|
|
||||||
scalar_flag = 1;
|
|
||||||
global_freq = nevery;
|
|
||||||
extscalar = 0;
|
|
||||||
|
|
||||||
if (strcmp(arg[4],"x") == 0) vdim = 0;
|
|
||||||
else if (strcmp(arg[4],"y") == 0) vdim = 1;
|
|
||||||
else if (strcmp(arg[4],"z") == 0) vdim = 2;
|
|
||||||
else error->all(FLERR,"Illegal fix viscosity command");
|
|
||||||
|
|
||||||
if (strcmp(arg[5],"x") == 0) pdim = 0;
|
|
||||||
else if (strcmp(arg[5],"y") == 0) pdim = 1;
|
|
||||||
else if (strcmp(arg[5],"z") == 0) pdim = 2;
|
|
||||||
else error->all(FLERR,"Illegal fix viscosity command");
|
|
||||||
|
|
||||||
nbin = force->inumeric(FLERR,arg[6]);
|
|
||||||
if (nbin % 2 || nbin <= 2) error->all(FLERR,"Illegal fix viscosity command");
|
|
||||||
|
|
||||||
// optional keywords
|
|
||||||
|
|
||||||
nswap = 1;
|
|
||||||
vtarget = BIG;
|
|
||||||
|
|
||||||
int iarg = 7;
|
|
||||||
while (iarg < narg) {
|
|
||||||
if (strcmp(arg[iarg],"swap") == 0) {
|
|
||||||
if (iarg+2 > narg) error->all(FLERR,"Illegal fix viscosity command");
|
|
||||||
nswap = force->inumeric(FLERR,arg[iarg+1]);
|
|
||||||
if (nswap <= 0)
|
|
||||||
error->all(FLERR,"Fix viscosity swap value must be positive");
|
|
||||||
iarg += 2;
|
|
||||||
} else if (strcmp(arg[iarg],"vtarget") == 0) {
|
|
||||||
if (iarg+2 > narg) error->all(FLERR,"Illegal fix viscosity command");
|
|
||||||
if (strcmp(arg[iarg+1],"INF") == 0) vtarget = BIG;
|
|
||||||
else vtarget = force->numeric(FLERR,arg[iarg+1]);
|
|
||||||
if (vtarget <= 0.0)
|
|
||||||
error->all(FLERR,"Fix viscosity vtarget value must be positive");
|
|
||||||
iarg += 2;
|
|
||||||
} else error->all(FLERR,"Illegal fix viscosity command");
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize array sizes to nswap+1 so have space to shift values down
|
|
||||||
|
|
||||||
pos_index = new int[nswap+1];
|
|
||||||
neg_index = new int[nswap+1];
|
|
||||||
pos_delta = new double[nswap+1];
|
|
||||||
neg_delta = new double[nswap+1];
|
|
||||||
|
|
||||||
p_exchange = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
FixViscosity::~FixViscosity()
|
|
||||||
{
|
|
||||||
delete [] pos_index;
|
|
||||||
delete [] neg_index;
|
|
||||||
delete [] pos_delta;
|
|
||||||
delete [] neg_delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
int FixViscosity::setmask()
|
|
||||||
{
|
|
||||||
int mask = 0;
|
|
||||||
mask |= END_OF_STEP;
|
|
||||||
return mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixViscosity::init()
|
|
||||||
{
|
|
||||||
// warn if any fix ave/spatial comes after this fix
|
|
||||||
// can cause glitch in averaging since ave will happen after swap
|
|
||||||
|
|
||||||
int foundme = 0;
|
|
||||||
for (int i = 0; i < modify->nfix; i++) {
|
|
||||||
if (modify->fix[i] == this) foundme = 1;
|
|
||||||
if (foundme && strcmp(modify->fix[i]->style,"ave/spatial") == 0 && me == 0)
|
|
||||||
error->warning(FLERR,"Fix viscosity comes before fix ave/spatial");
|
|
||||||
}
|
|
||||||
|
|
||||||
// set bounds of 2 slabs in pdim
|
|
||||||
// only necessary for static box, else re-computed in end_of_step()
|
|
||||||
// lo bin is always bottom bin
|
|
||||||
// hi bin is just above half height
|
|
||||||
|
|
||||||
if (domain->box_change == 0) {
|
|
||||||
prd = domain->prd[pdim];
|
|
||||||
boxlo = domain->boxlo[pdim];
|
|
||||||
boxhi = domain->boxhi[pdim];
|
|
||||||
double binsize = (boxhi-boxlo) / nbin;
|
|
||||||
slablo_lo = boxlo;
|
|
||||||
slablo_hi = boxlo + binsize;
|
|
||||||
slabhi_lo = boxlo + (nbin/2)*binsize;
|
|
||||||
slabhi_hi = boxlo + (nbin/2+1)*binsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
periodicity = domain->periodicity[pdim];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
void FixViscosity::end_of_step()
|
|
||||||
{
|
|
||||||
int i,m,insert;
|
|
||||||
double coord,delta;
|
|
||||||
MPI_Status status;
|
|
||||||
struct {
|
|
||||||
double value;
|
|
||||||
int proc;
|
|
||||||
} mine[2],all[2];
|
|
||||||
|
|
||||||
// if box changes, recompute bounds of 2 slabs in pdim
|
|
||||||
|
|
||||||
if (domain->box_change) {
|
|
||||||
prd = domain->prd[pdim];
|
|
||||||
boxlo = domain->boxlo[pdim];
|
|
||||||
boxhi = domain->boxhi[pdim];
|
|
||||||
double binsize = (boxhi-boxlo) / nbin;
|
|
||||||
slablo_lo = boxlo;
|
|
||||||
slablo_hi = boxlo + binsize;
|
|
||||||
slabhi_lo = boxlo + (nbin/2)*binsize;
|
|
||||||
slabhi_hi = boxlo + (nbin/2+1)*binsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make 2 lists of up to nswap atoms with velocity closest to +/- vtarget
|
|
||||||
// lists are sorted by closeness to vtarget
|
|
||||||
// only consider atoms in the bottom/middle slabs
|
|
||||||
// map atoms back into periodic box if necessary
|
|
||||||
// insert = location in list to insert new atom
|
|
||||||
|
|
||||||
double **x = atom->x;
|
|
||||||
double **v = atom->v;
|
|
||||||
int *type = atom->type;
|
|
||||||
int *mask = atom->mask;
|
|
||||||
int nlocal = atom->nlocal;
|
|
||||||
|
|
||||||
npositive = nnegative = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < nlocal; i++)
|
|
||||||
if (mask[i] & groupbit) {
|
|
||||||
coord = x[i][pdim];
|
|
||||||
if (coord < boxlo && periodicity) coord += prd;
|
|
||||||
else if (coord >= boxhi && periodicity) coord -= prd;
|
|
||||||
|
|
||||||
if (coord >= slablo_lo && coord < slablo_hi) {
|
|
||||||
if (v[i][vdim] < 0.0) continue;
|
|
||||||
delta = fabs(v[i][vdim] - vtarget);
|
|
||||||
if (npositive < nswap || delta < pos_delta[nswap-1]) {
|
|
||||||
for (insert = npositive-1; insert >= 0; insert--)
|
|
||||||
if (delta > pos_delta[insert]) break;
|
|
||||||
insert++;
|
|
||||||
for (m = npositive-1; m >= insert; m--) {
|
|
||||||
pos_delta[m+1] = pos_delta[m];
|
|
||||||
pos_index[m+1] = pos_index[m];
|
|
||||||
}
|
|
||||||
pos_delta[insert] = delta;
|
|
||||||
pos_index[insert] = i;
|
|
||||||
if (npositive < nswap) npositive++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coord >= slabhi_lo && coord < slabhi_hi) {
|
|
||||||
if (v[i][vdim] > 0.0) continue;
|
|
||||||
delta = fabs(v[i][vdim] + vtarget);
|
|
||||||
if (nnegative < nswap || delta < neg_delta[nswap-1]) {
|
|
||||||
for (insert = nnegative-1; insert >= 0; insert--)
|
|
||||||
if (delta > neg_delta[insert]) break;
|
|
||||||
insert++;
|
|
||||||
for (m = nnegative-1; m >= insert; m--) {
|
|
||||||
neg_delta[m+1] = neg_delta[m];
|
|
||||||
neg_index[m+1] = neg_index[m];
|
|
||||||
}
|
|
||||||
neg_delta[insert] = delta;
|
|
||||||
neg_index[insert] = i;
|
|
||||||
if (nnegative < nswap) nnegative++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop over nswap pairs
|
|
||||||
// find 2 global atoms with smallest delta in bottom/top slabs
|
|
||||||
// BIG values are for procs with no atom to contribute
|
|
||||||
// MINLOC also communicates which procs own them
|
|
||||||
// exchange momenta between the 2 particles
|
|
||||||
// if I own both particles just swap, else point2point comm of vel,mass
|
|
||||||
|
|
||||||
double *mass = atom->mass;
|
|
||||||
double *rmass = atom->rmass;
|
|
||||||
|
|
||||||
int ipos,ineg;
|
|
||||||
double sbuf[2],rbuf[2],vcm;
|
|
||||||
|
|
||||||
double pswap = 0.0;
|
|
||||||
mine[0].proc = mine[1].proc = me;
|
|
||||||
int ipositive = 0;
|
|
||||||
int inegative = 0;
|
|
||||||
|
|
||||||
for (m = 0; m < nswap; m++) {
|
|
||||||
if (ipositive < npositive) mine[0].value = pos_delta[ipositive];
|
|
||||||
else mine[0].value = BIG;
|
|
||||||
if (inegative < nnegative) mine[1].value = neg_delta[inegative];
|
|
||||||
else mine[1].value = BIG;
|
|
||||||
|
|
||||||
MPI_Allreduce(mine,all,2,MPI_DOUBLE_INT,MPI_MINLOC,world);
|
|
||||||
|
|
||||||
if (all[0].value == BIG || all[1].value == BIG) continue;
|
|
||||||
|
|
||||||
if (me == all[0].proc && me == all[1].proc) {
|
|
||||||
ipos = pos_index[ipositive++];
|
|
||||||
ineg = neg_index[inegative++];
|
|
||||||
rbuf[0] = v[ipos][vdim];
|
|
||||||
if (rmass) rbuf[1] = rmass[ipos];
|
|
||||||
else rbuf[1] = mass[type[ipos]];
|
|
||||||
sbuf[0] = v[ineg][vdim];
|
|
||||||
if (rmass) sbuf[1] = rmass[ineg];
|
|
||||||
else sbuf[1] = mass[type[ineg]];
|
|
||||||
vcm = (sbuf[1]*sbuf[0] + rbuf[1]*rbuf[0]) / (sbuf[1] + rbuf[1]);
|
|
||||||
v[ineg][vdim] = 2.0 * vcm - sbuf[0];
|
|
||||||
v[ipos][vdim] = 2.0 * vcm - rbuf[0];
|
|
||||||
pswap += rbuf[1] * (vcm - rbuf[0]) - sbuf[1] * (vcm - sbuf[0]);
|
|
||||||
|
|
||||||
} else if (me == all[0].proc) {
|
|
||||||
ipos = pos_index[ipositive++];
|
|
||||||
sbuf[0] = v[ipos][vdim];
|
|
||||||
if (rmass) sbuf[1] = rmass[ipos];
|
|
||||||
else sbuf[1] = mass[type[ipos]];
|
|
||||||
MPI_Sendrecv(sbuf,2,MPI_DOUBLE,all[1].proc,0,
|
|
||||||
rbuf,2,MPI_DOUBLE,all[1].proc,0,world,&status);
|
|
||||||
vcm = (sbuf[1]*sbuf[0] + rbuf[1]*rbuf[0]) / (sbuf[1] + rbuf[1]);
|
|
||||||
v[ipos][vdim] = 2.0 * vcm - sbuf[0];
|
|
||||||
pswap += sbuf[1] * (vcm - sbuf[0]);
|
|
||||||
|
|
||||||
} else if (me == all[1].proc) {
|
|
||||||
ineg = neg_index[inegative++];
|
|
||||||
sbuf[0] = v[ineg][vdim];
|
|
||||||
if (rmass) sbuf[1] = rmass[ineg];
|
|
||||||
else sbuf[1] = mass[type[ineg]];
|
|
||||||
MPI_Sendrecv(sbuf,2,MPI_DOUBLE,all[0].proc,0,
|
|
||||||
rbuf,2,MPI_DOUBLE,all[0].proc,0,world,&status);
|
|
||||||
vcm = (sbuf[1]*sbuf[0] + rbuf[1]*rbuf[0]) / (sbuf[1] + rbuf[1]);
|
|
||||||
v[ineg][vdim] = 2.0 * vcm - sbuf[0];
|
|
||||||
pswap -= sbuf[1] * (vcm - sbuf[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tally momentum exchange from all swaps
|
|
||||||
|
|
||||||
double pswap_all;
|
|
||||||
MPI_Allreduce(&pswap,&pswap_all,1,MPI_DOUBLE,MPI_SUM,world);
|
|
||||||
p_exchange += pswap_all;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
double FixViscosity::compute_scalar()
|
|
||||||
{
|
|
||||||
return p_exchange;
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
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.
|
|
||||||
------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
#ifdef FIX_CLASS
|
|
||||||
|
|
||||||
FixStyle(viscosity,FixViscosity)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifndef LMP_FIX_VISCOSITY_H
|
|
||||||
#define LMP_FIX_VISCOSITY_H
|
|
||||||
|
|
||||||
#include "fix.h"
|
|
||||||
|
|
||||||
namespace LAMMPS_NS {
|
|
||||||
|
|
||||||
class FixViscosity : public Fix {
|
|
||||||
public:
|
|
||||||
FixViscosity(class LAMMPS *, int, char **);
|
|
||||||
~FixViscosity();
|
|
||||||
int setmask();
|
|
||||||
void init();
|
|
||||||
void end_of_step();
|
|
||||||
double compute_scalar();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int me;
|
|
||||||
int vdim,pdim,nbin,periodicity;
|
|
||||||
int nswap;
|
|
||||||
double vtarget;
|
|
||||||
double prd,boxlo,boxhi;
|
|
||||||
double slablo_lo,slablo_hi,slabhi_lo,slabhi_hi;
|
|
||||||
double p_exchange;
|
|
||||||
|
|
||||||
int npositive,nnegative;
|
|
||||||
int *pos_index,*neg_index;
|
|
||||||
double *pos_delta,*neg_delta;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ERROR/WARNING messages:
|
|
||||||
|
|
||||||
E: Illegal ... command
|
|
||||||
|
|
||||||
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: Fix viscosity swap value must be positive
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
E: Fix viscosity vtarget value must be positive
|
|
||||||
|
|
||||||
Self-explanatory.
|
|
||||||
|
|
||||||
W: Fix viscosity comes before fix ave/spatial
|
|
||||||
|
|
||||||
The order of these 2 fixes in your input script is such that
|
|
||||||
fix viscosity comes first. If you are using fix ave/spatial
|
|
||||||
to measure the velocity profile induced by fix viscosity, then
|
|
||||||
this may cause a glitch in the profile since you are averaging
|
|
||||||
immediately after swaps have occurred. Flipping the order
|
|
||||||
of the 2 fixes typically helps.
|
|
||||||
|
|
||||||
*/
|
|
Loading…
Reference in New Issue