Files
lammps/src/create_atoms.cpp

263 lines
8.6 KiB
C++

/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "create_atoms.h"
#include "atom.h"
#include "atom_vec.h"
#include "atom_vec_hybrid.h"
#include "comm.h"
#include "domain.h"
#include "lattice.h"
#include "region.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MAXATOMS 0x7FFFFFFF
#define BIG 1.0e30
#define EPSILON 1.0e-6
/* ---------------------------------------------------------------------- */
CreateAtoms::CreateAtoms(LAMMPS *lmp) : Pointers(lmp) {}
/* ---------------------------------------------------------------------- */
void CreateAtoms::command(int narg, char **arg)
{
if (domain->box_exist == 0)
error->all("Create_atoms command before simulation box is defined");
if (domain->lattice == NULL)
error->all("Cannot create atoms with undefined lattice");
// parse arguments
int nbasis = domain->lattice->nbasis;
int *basistype = new int[nbasis];
if (narg < 1) error->all("Illegal create_atoms command");
int itype = atoi(arg[0]);
if (itype <= 0 || itype > atom->ntypes)
error->all("Invalid atom type in create_atoms command");
for (int i = 0; i < nbasis; i++) basistype[i] = itype;
int regionflag = -1;
int nhybrid = 0;
int iarg = 1;
while (iarg < narg) {
if (strcmp(arg[iarg],"region") == 0) {
if (iarg+2 > narg) error->all("Illegal create_atoms command");
int iregion;
for (iregion = 0; iregion < domain->nregion; iregion++)
if (strcmp(arg[iarg+1],domain->regions[iregion]->id) == 0) break;
if (iregion == domain->nregion)
error->all("Create_atoms region ID does not exist");
regionflag = iregion;
iarg += 2;
} else if (strcmp(arg[iarg],"basis") == 0) {
if (iarg+3 > narg) error->all("Illegal create_atoms command");
int ibasis = atoi(arg[iarg+1]);
itype = atoi(arg[iarg+2]);
if (ibasis <= 0 || ibasis > nbasis ||
itype <= 0 || itype > atom->ntypes)
error->all("Illegal create_atoms command");
basistype[ibasis-1] = itype;
iarg += 3;
} else if (strcmp(arg[iarg],"hybrid") == 0) {
if (iarg+3 > narg) error->all("Illegal create_atoms command");
AtomVecHybrid *avec_hybrid = (AtomVecHybrid *) atom->avec;
int ihybrid;
for (ihybrid = 0; ihybrid < avec_hybrid->nstyles; ihybrid++)
if (strcmp(avec_hybrid->keywords[ihybrid],arg[iarg+1]) == 0) break;
if (ihybrid == avec_hybrid->nstyles)
error->all("Create atoms hybrid sub-style does not exist");
nhybrid = ihybrid;
iarg += 3;
} else error->all("Illegal create_atoms command");
}
// convert 8 corners of my subdomain from box coords to lattice coords
// for orthogonal, use corner pts of my subbox
// for triclinic, use bounding box of my subbox
// xyz min to max = bounding box around the domain corners in lattice space
int triclinic = domain->triclinic;
double bboxlo[3],bboxhi[3];
if (triclinic == 0) {
bboxlo[0] = domain->sublo[0]; bboxhi[0] = domain->subhi[0];
bboxlo[1] = domain->sublo[1]; bboxhi[1] = domain->subhi[1];
bboxlo[2] = domain->sublo[2]; bboxhi[2] = domain->subhi[2];
} else domain->bbox(domain->sublo_lamda,domain->subhi_lamda,bboxlo,bboxhi);
double xmin,ymin,zmin,xmax,ymax,zmax;
xmin = ymin = zmin = BIG;
xmax = ymax = zmax = -BIG;
domain->lattice->bbox(1,bboxlo[0],bboxlo[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxlo[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxlo[0],bboxhi[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxhi[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxlo[0],bboxlo[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxlo[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxlo[0],bboxhi[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxhi[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
// ilo:ihi,jlo:jhi,klo:khi = loop bounds for lattice overlap of my subbox
// overlap = any part of a unit cell (face,edge,pt) in common with my subbox
// in lattice space, subbox is a tilted box
// but bbox of subbox is aligned with lattice axes
// so ilo:khi unit cells should completely tile bounding box
// decrement lo values if min < 0, since static_cast(-1.5) = -1
int ilo,ihi,jlo,jhi,klo,khi;
ilo = static_cast<int> (xmin);
jlo = static_cast<int> (ymin);
klo = static_cast<int> (zmin);
ihi = static_cast<int> (xmax);
jhi = static_cast<int> (ymax);
khi = static_cast<int> (zmax);
if (xmin < 0.0) ilo--;
if (ymin < 0.0) jlo--;
if (zmin < 0.0) klo--;
// set bounds for my proc
// if periodic and I am lo/hi proc, adjust bounds by EPSILON
// on lower boundary, allows triclinic atoms just outside box to be added
// on upper boundary, prevents atoms with lower images from being added
double sublo[3],subhi[3];
if (triclinic == 0) {
sublo[0] = domain->sublo[0]; subhi[0] = domain->subhi[0];
sublo[1] = domain->sublo[1]; subhi[1] = domain->subhi[1];
sublo[2] = domain->sublo[2]; subhi[2] = domain->subhi[2];
} else {
sublo[0] = domain->sublo_lamda[0]; subhi[0] = domain->subhi_lamda[0];
sublo[1] = domain->sublo_lamda[1]; subhi[1] = domain->subhi_lamda[1];
sublo[2] = domain->sublo_lamda[2]; subhi[2] = domain->subhi_lamda[2];
}
if (domain->xperiodic) {
if (triclinic && comm->myloc[0] == 0) sublo[0] -= EPSILON;
if (comm->myloc[0] == comm->procgrid[0]-1) subhi[0] -= EPSILON;
}
if (domain->yperiodic) {
if (triclinic && comm->myloc[1] == 0) sublo[1] -= EPSILON;
if (comm->myloc[1] == comm->procgrid[1]-1) subhi[1] -= EPSILON;
}
if (domain->zperiodic) {
if (triclinic && comm->myloc[2] == 0) sublo[2] -= EPSILON;
if (comm->myloc[2] == comm->procgrid[2]-1) subhi[2] -= EPSILON;
}
// iterate on 3d periodic lattice using loop bounds
// invoke add_atom for nbasis atoms in each unit cell
// converts lattice coords to box coords
// add atom if it meets all criteria
double natoms_previous = atom->natoms;
int nlocal_previous = atom->nlocal;
double **basis = domain->lattice->basis;
double x[3],lamda[3];
double *coord;
int i,j,k,m;
for (k = klo; k <= khi; k++)
for (j = jlo; j <= jhi; j++)
for (i = ilo; i <= ihi; i++)
for (m = 0; m < nbasis; m++) {
x[0] = i + basis[m][0];
x[1] = j + basis[m][1];
x[2] = k + basis[m][2];
// convert from lattice coords to box coords
domain->lattice->lattice2box(x[0],x[1],x[2]);
// if a region was specified, test if atom is in it
if (regionflag >= 0)
if (!domain->regions[regionflag]->match(x[0],x[1],x[2])) continue;
// test if atom is in my subbox
if (triclinic) {
domain->x2lamda(x,lamda);
coord = lamda;
} else coord = x;
if (coord[0] < sublo[0] || coord[0] >= subhi[0] ||
coord[1] < sublo[1] || coord[1] >= subhi[1] ||
coord[2] < sublo[2] || coord[2] >= subhi[2]) continue;
// add the atom to my list of atoms
atom->avec->create_atom(basistype[m],x,nhybrid);
}
// clean up
delete [] basistype;
// new total # of atoms
double rlocal = atom->nlocal;
MPI_Allreduce(&rlocal,&atom->natoms,1,MPI_DOUBLE,MPI_SUM,world);
// print status
if (comm->me == 0) {
if (screen)
fprintf(screen,"Created %.15g atoms\n",atom->natoms-natoms_previous);
if (logfile)
fprintf(logfile,"Created %.15g atoms\n",atom->natoms-natoms_previous);
}
// reset simulation now that more atoms are defined
// add tags for newly created atoms if possible
// if global map exists, reset it
// if a molecular system, set nspecial to 0 for new atoms
if (atom->natoms > MAXATOMS) atom->tag_enable = 0;
if (atom->natoms <= MAXATOMS) atom->tag_extend();
if (atom->map_style) {
atom->map_init();
atom->map_set();
}
if (atom->molecular) {
int **nspecial = atom->nspecial;
for (i = nlocal_previous; i < atom->nlocal; i++) {
nspecial[i][0] = 0;
nspecial[i][1] = 0;
nspecial[i][2] = 0;
}
}
}