/* ---------------------------------------------------------------------- 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 = atoi(arg[3]); ntype = atoi(arg[4]); nfreq = atoi(arg[5]); seed = atoi(arg[6]); if (seed <= 0) error->all(FLERR,"Illegal fix deposit command"); // set defaults iregion = -1; idregion = NULL; 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 if (scaleflag && domain->lattice == NULL) error->all(FLERR,"Use of fix deposit with undefined lattice"); 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; // 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 // set tag # of new particle beyond all previous atoms // if global map exists, reset it now instead of waiting for comm // since deleting atoms messes up ghosts if (success) { atom->natoms += 1; if (atom->tag_enable) { 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],"global") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command"); globalflag = 1; localflag = 0; lo = atof(arg[iarg+1]); hi = atof(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 = atof(arg[iarg+1]); hi = atof(arg[iarg+2]); deltasq = atof(arg[iarg+3])*atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"near") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command"); nearsq = atof(arg[iarg+1])*atof(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"attempt") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command"); maxattempt = atoi(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 = atof(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"vx") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command"); vxlo = atof(arg[iarg+1]); vxhi = atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"vy") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command"); vylo = atof(arg[iarg+1]); vyhi = atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"vz") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command"); vzlo = atof(arg[iarg+1]); vzhi = atof(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 = atof(arg[iarg+1]); ty = atof(arg[iarg+2]); tz = atof(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 (list[n++]); ninserted = static_cast (list[n++]); nfirst = static_cast (list[n++]); next_reneighbor = static_cast (list[n++]); random->reset(seed); }